@lodestar/beacon-node 1.36.0-dev.a2a22d66ef → 1.36.0-dev.a47974e6c6
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 +23 -13
- package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.js +5 -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 +45 -17
- 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 +8 -8
- package/lib/network/core/networkCoreWorker.js.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.js +1 -1
- package/lib/network/core/networkCoreWorkerHandler.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/events.d.ts +1 -0
- package/lib/network/events.d.ts.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/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/ReqRespBeaconNode.d.ts.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js +3 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -3
- 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/reqresp/handlers/dataColumnSidecarsByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +9 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts +2 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +9 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +6 -6
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/types.d.ts +1 -0
- package/lib/network/reqresp/types.d.ts.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/downloadByRange.d.ts +58 -13
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +201 -82
- package/lib/sync/utils/downloadByRange.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 +27 -13
- 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 +54 -19
- 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 +9 -9
- package/src/network/core/networkCoreWorkerHandler.ts +1 -1
- package/src/network/discv5/utils.ts +1 -2
- package/src/network/discv5/worker.ts +2 -7
- package/src/network/events.ts +1 -1
- 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/options.ts +0 -1
- package/src/network/processor/gossipHandlers.ts +16 -7
- package/src/network/reqresp/ReqRespBeaconNode.ts +3 -1
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +18 -3
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +6 -6
- package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +5 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +13 -1
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +13 -1
- package/src/network/reqresp/handlers/index.ts +6 -6
- package/src/network/reqresp/types.ts +1 -0
- 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/downloadByRange.ts +259 -103
- 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
|
@@ -654,18 +654,21 @@ export function getBeaconBlockApi({
|
|
|
654
654
|
);
|
|
655
655
|
}
|
|
656
656
|
|
|
657
|
-
const
|
|
657
|
+
for (const index of indices ?? []) {
|
|
658
|
+
if (index < 0 || index >= blobCount) {
|
|
659
|
+
throw new ApiError(400, `Invalid blob index ${index}, must be between 0 and ${blobCount - 1}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const indicesToReconstruct = indices ?? Array.from({length: blobCount}, (_, i) => i);
|
|
664
|
+
const blobs = await reconstructBlobs(dataColumnSidecars, indicesToReconstruct);
|
|
658
665
|
const signedBlockHeader = signedBlockToSignedHeader(config, block);
|
|
659
|
-
const requestedIndices = indices ?? Array.from({length: blobKzgCommitments.length}, (_, i) => i);
|
|
660
666
|
|
|
661
667
|
data = await Promise.all(
|
|
662
|
-
|
|
668
|
+
indicesToReconstruct.map(async (index, i) => {
|
|
663
669
|
// Reconstruct blob sidecar from blob
|
|
664
670
|
const kzgCommitment = blobKzgCommitments[index];
|
|
665
|
-
|
|
666
|
-
throw new ApiError(400, `Blob index ${index} not found in block`);
|
|
667
|
-
}
|
|
668
|
-
const blob = blobs[index];
|
|
671
|
+
const blob = blobs[i]; // Use i since blobs only contains requested indices
|
|
669
672
|
const kzgProof = await kzg.asyncComputeBlobKzgProof(blob, kzgCommitment);
|
|
670
673
|
const kzgCommitmentInclusionProof = computePreFuluKzgCommitmentsInclusionProof(
|
|
671
674
|
fork,
|
|
@@ -724,7 +727,8 @@ export function getBeaconBlockApi({
|
|
|
724
727
|
);
|
|
725
728
|
}
|
|
726
729
|
|
|
727
|
-
const
|
|
730
|
+
const blobKzgCommitments = (block.message.body as deneb.BeaconBlockBody).blobKzgCommitments;
|
|
731
|
+
const blobCount = blobKzgCommitments.length;
|
|
728
732
|
|
|
729
733
|
if (blobCount > 0) {
|
|
730
734
|
let dataColumnSidecars = await fromAsync(db.dataColumnSidecar.valuesStream(blockRoot));
|
|
@@ -739,7 +743,25 @@ export function getBeaconBlockApi({
|
|
|
739
743
|
);
|
|
740
744
|
}
|
|
741
745
|
|
|
742
|
-
|
|
746
|
+
let indicesToReconstruct: number[];
|
|
747
|
+
if (versionedHashes) {
|
|
748
|
+
const blockVersionedHashes = blobKzgCommitments.map((commitment) =>
|
|
749
|
+
toHex(kzgCommitmentToVersionedHash(commitment))
|
|
750
|
+
);
|
|
751
|
+
indicesToReconstruct = [];
|
|
752
|
+
for (const requestedHash of versionedHashes) {
|
|
753
|
+
const index = blockVersionedHashes.findIndex((hash) => hash === requestedHash);
|
|
754
|
+
if (index === -1) {
|
|
755
|
+
throw new ApiError(400, `Versioned hash ${requestedHash} not found in block`);
|
|
756
|
+
}
|
|
757
|
+
indicesToReconstruct.push(index);
|
|
758
|
+
}
|
|
759
|
+
indicesToReconstruct.sort((a, b) => a - b);
|
|
760
|
+
} else {
|
|
761
|
+
indicesToReconstruct = Array.from({length: blobCount}, (_, i) => i);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
blobs = await reconstructBlobs(dataColumnSidecars, indicesToReconstruct);
|
|
743
765
|
} else {
|
|
744
766
|
blobs = [];
|
|
745
767
|
}
|
|
@@ -757,27 +779,27 @@ export function getBeaconBlockApi({
|
|
|
757
779
|
}
|
|
758
780
|
|
|
759
781
|
blobs = blobSidecars.sort((a, b) => a.index - b.index).map(({blob}) => blob);
|
|
760
|
-
} else {
|
|
761
|
-
blobs = [];
|
|
762
|
-
}
|
|
763
782
|
|
|
764
|
-
|
|
765
|
-
|
|
783
|
+
if (blobs.length && versionedHashes) {
|
|
784
|
+
const kzgCommitments = (block as deneb.SignedBeaconBlock).message.body.blobKzgCommitments;
|
|
766
785
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
786
|
+
const blockVersionedHashes = kzgCommitments.map((commitment) =>
|
|
787
|
+
toHex(kzgCommitmentToVersionedHash(commitment))
|
|
788
|
+
);
|
|
770
789
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
790
|
+
const requestedIndices: number[] = [];
|
|
791
|
+
for (const requestedHash of versionedHashes) {
|
|
792
|
+
const index = blockVersionedHashes.findIndex((hash) => hash === requestedHash);
|
|
793
|
+
if (index === -1) {
|
|
794
|
+
throw new ApiError(400, `Versioned hash ${requestedHash} not found in block`);
|
|
795
|
+
}
|
|
796
|
+
requestedIndices.push(index);
|
|
776
797
|
}
|
|
777
|
-
requestedIndices.push(index);
|
|
778
|
-
}
|
|
779
798
|
|
|
780
|
-
|
|
799
|
+
blobs = requestedIndices.sort((a, b) => a - b).map((index) => blobs[index]);
|
|
800
|
+
}
|
|
801
|
+
} else {
|
|
802
|
+
blobs = [];
|
|
781
803
|
}
|
|
782
804
|
|
|
783
805
|
return {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ATTESTATION_SUBNET_COUNT,
|
|
3
|
+
ATTESTATION_SUBNET_EXTRA_BITS,
|
|
4
|
+
ATTESTATION_SUBNET_PREFIX_BITS,
|
|
3
5
|
BASE_REWARDS_PER_EPOCH,
|
|
4
6
|
BLOB_TX_TYPE,
|
|
5
7
|
BLS_WITHDRAWAL_PREFIX,
|
|
@@ -25,15 +27,15 @@ import {
|
|
|
25
27
|
DOMAIN_SYNC_COMMITTEE,
|
|
26
28
|
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF,
|
|
27
29
|
DOMAIN_VOLUNTARY_EXIT,
|
|
28
|
-
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION,
|
|
29
30
|
ETH1_ADDRESS_WITHDRAWAL_PREFIX,
|
|
30
31
|
FAR_FUTURE_EPOCH,
|
|
31
32
|
FULL_EXIT_REQUEST_AMOUNT,
|
|
32
33
|
GENESIS_EPOCH,
|
|
33
34
|
GENESIS_SLOT,
|
|
34
35
|
JUSTIFICATION_BITS_LENGTH,
|
|
36
|
+
MAX_CONCURRENT_REQUESTS,
|
|
37
|
+
NODE_ID_BITS,
|
|
35
38
|
PROPOSER_WEIGHT,
|
|
36
|
-
RANDOM_SUBNETS_PER_VALIDATOR,
|
|
37
39
|
SYNC_COMMITTEE_SUBNET_COUNT,
|
|
38
40
|
SYNC_REWARD_WEIGHT,
|
|
39
41
|
TARGET_AGGREGATORS_PER_COMMITTEE,
|
|
@@ -84,9 +86,13 @@ export const specConstants = {
|
|
|
84
86
|
|
|
85
87
|
// phase0/validator.md
|
|
86
88
|
TARGET_AGGREGATORS_PER_COMMITTEE,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
|
|
90
|
+
// phase0/p2p-interface.md
|
|
91
|
+
NODE_ID_BITS,
|
|
92
|
+
MAX_CONCURRENT_REQUESTS,
|
|
89
93
|
ATTESTATION_SUBNET_COUNT,
|
|
94
|
+
ATTESTATION_SUBNET_EXTRA_BITS,
|
|
95
|
+
ATTESTATION_SUBNET_PREFIX_BITS,
|
|
90
96
|
|
|
91
97
|
// altair/beacon-chain.md
|
|
92
98
|
// ## Participation flag indices
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import {Tree} from "@chainsafe/persistent-merkle-tree";
|
|
4
2
|
import {routes} from "@lodestar/api";
|
|
5
3
|
import {ApplicationMethods} from "@lodestar/api/server";
|
|
@@ -8,13 +6,16 @@ import {Repository} from "@lodestar/db";
|
|
|
8
6
|
import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
9
7
|
import {BeaconStateCapella, getLatestWeakSubjectivityCheckpointEpoch, loadState} from "@lodestar/state-transition";
|
|
10
8
|
import {ssz} from "@lodestar/types";
|
|
11
|
-
import {
|
|
9
|
+
import {Checkpoint} from "@lodestar/types/phase0";
|
|
10
|
+
import {fromHex, toHex, toRootHex} from "@lodestar/utils";
|
|
12
11
|
import {BeaconChain} from "../../../chain/index.js";
|
|
13
12
|
import {QueuedStateRegenerator, RegenRequest} from "../../../chain/regen/index.js";
|
|
14
13
|
import {IBeaconDb} from "../../../db/interface.js";
|
|
15
14
|
import {GossipType} from "../../../network/index.js";
|
|
16
|
-
import {
|
|
15
|
+
import {getStateSlotFromBytes} from "../../../util/multifork.js";
|
|
16
|
+
import {ProfileThread, profileThread, writeHeapSnapshot} from "../../../util/profile.js";
|
|
17
17
|
import {getStateResponseWithRegen} from "../beacon/state/utils.js";
|
|
18
|
+
import {ApiError} from "../errors.js";
|
|
18
19
|
import {ApiModules} from "../types.js";
|
|
19
20
|
|
|
20
21
|
export function getLodestarApi({
|
|
@@ -26,7 +27,9 @@ export function getLodestarApi({
|
|
|
26
27
|
}: Pick<ApiModules, "chain" | "config" | "db" | "network" | "sync">): ApplicationMethods<routes.lodestar.Endpoints> {
|
|
27
28
|
let writingHeapdump = false;
|
|
28
29
|
let writingProfile = false;
|
|
29
|
-
|
|
30
|
+
// for NodeJS, profile the whole epoch
|
|
31
|
+
// for Bun, profile 1 slot. Otherwise it will either crash the app, and/or inspector cannot render the profile
|
|
32
|
+
const defaultProfileMs = globalThis.Bun ? config.SLOT_DURATION_MS : SLOTS_PER_EPOCH * config.SLOT_DURATION_MS;
|
|
30
33
|
|
|
31
34
|
return {
|
|
32
35
|
async writeHeapdump({thread = "main", dirpath = "."}) {
|
|
@@ -63,7 +66,6 @@ export function getLodestarApi({
|
|
|
63
66
|
|
|
64
67
|
try {
|
|
65
68
|
let filepath: string;
|
|
66
|
-
let profile: string;
|
|
67
69
|
switch (thread) {
|
|
68
70
|
case "network":
|
|
69
71
|
filepath = await network.writeNetworkThreadProfile(duration, dirpath);
|
|
@@ -73,12 +75,10 @@ export function getLodestarApi({
|
|
|
73
75
|
break;
|
|
74
76
|
default:
|
|
75
77
|
// main thread
|
|
76
|
-
|
|
77
|
-
filepath = path.join(dirpath, `main_thread_${new Date().toISOString()}.cpuprofile`);
|
|
78
|
-
fs.writeFileSync(filepath, profile);
|
|
78
|
+
filepath = await profileThread(ProfileThread.MAIN, duration, dirpath);
|
|
79
79
|
break;
|
|
80
80
|
}
|
|
81
|
-
return {data: {filepath}};
|
|
81
|
+
return {data: {result: filepath}};
|
|
82
82
|
} finally {
|
|
83
83
|
writingProfile = false;
|
|
84
84
|
}
|
|
@@ -218,6 +218,26 @@ export function getLodestarApi({
|
|
|
218
218
|
meta: {executionOptimistic, finalized, version: fork},
|
|
219
219
|
};
|
|
220
220
|
},
|
|
221
|
+
|
|
222
|
+
// the optional checkpoint is in root:epoch format
|
|
223
|
+
async getPersistedCheckpointState({checkpointId}) {
|
|
224
|
+
const checkpoint = checkpointId ? getCheckpointFromArg(checkpointId) : undefined;
|
|
225
|
+
const stateBytes = await chain.getPersistedCheckpointState(checkpoint);
|
|
226
|
+
if (stateBytes === null) {
|
|
227
|
+
throw new ApiError(
|
|
228
|
+
404,
|
|
229
|
+
checkpointId ? `Checkpoint state not found for id ${checkpointId}` : "Latest safe checkpoint state not found"
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const slot = getStateSlotFromBytes(stateBytes);
|
|
234
|
+
return {
|
|
235
|
+
data: stateBytes,
|
|
236
|
+
meta: {
|
|
237
|
+
version: config.getForkName(slot),
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
},
|
|
221
241
|
};
|
|
222
242
|
}
|
|
223
243
|
|
|
@@ -247,6 +267,18 @@ function regenRequestToJson(config: ChainForkConfig, regenRequest: RegenRequest)
|
|
|
247
267
|
}
|
|
248
268
|
}
|
|
249
269
|
|
|
270
|
+
const CHECKPOINT_REGEX = /^(?:0x)?([0-9a-f]{64}):([0-9]+)$/;
|
|
271
|
+
/**
|
|
272
|
+
* Extract a checkpoint from a string in the format `rootHex:epoch`.
|
|
273
|
+
*/
|
|
274
|
+
export function getCheckpointFromArg(checkpointStr: string): Checkpoint {
|
|
275
|
+
const match = CHECKPOINT_REGEX.exec(checkpointStr.toLowerCase());
|
|
276
|
+
if (!match) {
|
|
277
|
+
throw new ApiError(400, `Could not parse checkpoint string: ${checkpointStr}`);
|
|
278
|
+
}
|
|
279
|
+
return {root: fromHex(match[1]), epoch: parseInt(match[2])};
|
|
280
|
+
}
|
|
281
|
+
|
|
250
282
|
function stringifyKeys(keys: (Uint8Array | number | string)[]): string[] {
|
|
251
283
|
return keys.map((key) => {
|
|
252
284
|
if (key instanceof Uint8Array) {
|
|
@@ -10,7 +10,7 @@ export function formatNodePeer(peerIdStr: string, connections: Connection[]): ro
|
|
|
10
10
|
return {
|
|
11
11
|
peerId: conn ? conn.remotePeer.toString() : peerIdStr,
|
|
12
12
|
// TODO: figure out how to get enr of peer
|
|
13
|
-
enr:
|
|
13
|
+
enr: null,
|
|
14
14
|
lastSeenP2pAddress: conn ? conn.remoteAddr.toString() : "",
|
|
15
15
|
direction: conn ? (conn.direction as routes.node.PeerDirection) : null,
|
|
16
16
|
state: conn ? getPeerState(conn.status) : "disconnected",
|
|
@@ -179,10 +179,13 @@ export function getValidatorApi(
|
|
|
179
179
|
/**
|
|
180
180
|
* Validator clock may be advanced from beacon's clock. If the validator requests a resource in a
|
|
181
181
|
* future slot, wait some time instead of rejecting the request because it's in the future.
|
|
182
|
-
* This value is the same to
|
|
182
|
+
* This value is the same to MAXIMUM_GOSSIP_CLOCK_DISPARITY.
|
|
183
183
|
* For very fast networks, reduce clock disparity to half a slot.
|
|
184
184
|
*/
|
|
185
|
-
const MAX_API_CLOCK_DISPARITY_SEC = Math.min(
|
|
185
|
+
const MAX_API_CLOCK_DISPARITY_SEC = Math.min(
|
|
186
|
+
config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000,
|
|
187
|
+
config.SLOT_DURATION_MS / 2000
|
|
188
|
+
);
|
|
186
189
|
const MAX_API_CLOCK_DISPARITY_MS = MAX_API_CLOCK_DISPARITY_SEC * 1000;
|
|
187
190
|
|
|
188
191
|
/** Compute and cache the genesis block root */
|
|
@@ -25,6 +25,16 @@ type ArchiveStoreModules = {
|
|
|
25
25
|
|
|
26
26
|
type ArchiveStoreInitOpts = ArchiveStoreOpts & {dbName: string; anchorState: {finalizedCheckpoint: Checkpoint}};
|
|
27
27
|
|
|
28
|
+
export enum ArchiveStoreTask {
|
|
29
|
+
ArchiveBlocks = "archive_blocks",
|
|
30
|
+
PruneHistory = "prune_history",
|
|
31
|
+
OnFinalizedCheckpoint = "on_finalized_checkpoint",
|
|
32
|
+
MaybeArchiveState = "maybe_archive_state",
|
|
33
|
+
RegenPruneOnFinalized = "regen_prune_on_finalized",
|
|
34
|
+
ForkchoicePrune = "forkchoice_prune",
|
|
35
|
+
UpdateBackfillRange = "update_backfill_range",
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
/**
|
|
29
39
|
* Used for running tasks that depends on some events or are executed
|
|
30
40
|
* periodically.
|
|
@@ -176,6 +186,8 @@ export class ArchiveStore {
|
|
|
176
186
|
try {
|
|
177
187
|
const finalizedEpoch = finalized.epoch;
|
|
178
188
|
this.logger.verbose("Start processing finalized checkpoint", {epoch: finalizedEpoch, rootHex: finalized.rootHex});
|
|
189
|
+
|
|
190
|
+
let timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
179
191
|
await archiveBlocks(
|
|
180
192
|
this.chain.config,
|
|
181
193
|
this.db,
|
|
@@ -188,7 +200,10 @@ export class ArchiveStore {
|
|
|
188
200
|
this.chain.opts.persistOrphanedBlocks,
|
|
189
201
|
this.chain.opts.persistOrphanedBlocksDir
|
|
190
202
|
);
|
|
203
|
+
timer?.({source: ArchiveStoreTask.ArchiveBlocks});
|
|
204
|
+
|
|
191
205
|
if (this.opts.pruneHistory) {
|
|
206
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
192
207
|
await pruneHistory(
|
|
193
208
|
this.chain.config,
|
|
194
209
|
this.db,
|
|
@@ -197,18 +212,30 @@ export class ArchiveStore {
|
|
|
197
212
|
finalizedEpoch,
|
|
198
213
|
this.chain.clock.currentEpoch
|
|
199
214
|
);
|
|
215
|
+
timer?.({source: ArchiveStoreTask.PruneHistory});
|
|
200
216
|
}
|
|
201
217
|
|
|
218
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
202
219
|
await this.statesArchiverStrategy.onFinalizedCheckpoint(finalized, this.metrics);
|
|
220
|
+
timer?.({source: ArchiveStoreTask.OnFinalizedCheckpoint});
|
|
203
221
|
|
|
204
222
|
// should be after ArchiveBlocksTask to handle restart cleanly
|
|
223
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
205
224
|
await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics);
|
|
225
|
+
timer?.({source: ArchiveStoreTask.MaybeArchiveState});
|
|
206
226
|
|
|
227
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
207
228
|
this.chain.regen.pruneOnFinalized(finalizedEpoch);
|
|
229
|
+
timer?.({source: ArchiveStoreTask.RegenPruneOnFinalized});
|
|
208
230
|
|
|
209
231
|
// tasks rely on extended fork choice
|
|
232
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
210
233
|
const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex);
|
|
234
|
+
timer?.({source: ArchiveStoreTask.ForkchoicePrune});
|
|
235
|
+
|
|
236
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
211
237
|
await updateBackfillRange({chain: this.chain, db: this.db, logger: this.logger}, finalized);
|
|
238
|
+
timer?.({source: ArchiveStoreTask.UpdateBackfillRange});
|
|
212
239
|
|
|
213
240
|
this.logger.verbose("Finish processing finalized checkpoint", {
|
|
214
241
|
epoch: finalizedEpoch,
|
|
@@ -17,6 +17,15 @@ import {StateArchiveStrategy, StatesArchiveOpts} from "../interface.js";
|
|
|
17
17
|
*/
|
|
18
18
|
export const PERSIST_TEMP_STATE_EVERY_EPOCHS = 32;
|
|
19
19
|
|
|
20
|
+
export enum FrequencyStateArchiveStep {
|
|
21
|
+
LoadLastStoredSlot = "load_last_stored_slot",
|
|
22
|
+
GetFinalizedState = "get_finalized_state",
|
|
23
|
+
// SerializeState is tracked via stateSerializeDuration metric
|
|
24
|
+
PersistState = "persist_state",
|
|
25
|
+
LoadStoredSlotsToDelete = "load_stored_slots_to_delete",
|
|
26
|
+
DeleteOldStates = "delete_old_states",
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
/**
|
|
21
30
|
* Archives finalized states from active bucket to archive bucket.
|
|
22
31
|
*
|
|
@@ -47,11 +56,16 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
47
56
|
* ```
|
|
48
57
|
*/
|
|
49
58
|
async maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise<void> {
|
|
59
|
+
let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
50
60
|
const lastStoredSlot = await this.db.stateArchive.lastKey();
|
|
61
|
+
timer?.({step: FrequencyStateArchiveStep.LoadLastStoredSlot});
|
|
62
|
+
|
|
51
63
|
const lastStoredEpoch = computeEpochAtSlot(lastStoredSlot ?? 0);
|
|
52
64
|
const {archiveStateEpochFrequency} = this.opts;
|
|
53
65
|
|
|
66
|
+
const logCtx = {finalizedEpoch: finalized.epoch, lastStoredEpoch, archiveStateEpochFrequency};
|
|
54
67
|
if (finalized.epoch - lastStoredEpoch >= Math.min(PERSIST_TEMP_STATE_EVERY_EPOCHS, archiveStateEpochFrequency)) {
|
|
68
|
+
this.logger.verbose("Start archiving state", logCtx);
|
|
55
69
|
await this.archiveState(finalized, metrics);
|
|
56
70
|
|
|
57
71
|
// Only check the current and previous intervals
|
|
@@ -60,23 +74,29 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
60
74
|
(Math.floor(finalized.epoch / archiveStateEpochFrequency) - 1) * archiveStateEpochFrequency
|
|
61
75
|
);
|
|
62
76
|
|
|
77
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
63
78
|
const storedStateSlots = await this.db.stateArchive.keys({
|
|
64
79
|
lt: computeStartSlotAtEpoch(finalized.epoch),
|
|
65
80
|
gte: computeStartSlotAtEpoch(minEpoch),
|
|
66
81
|
});
|
|
82
|
+
timer?.({step: FrequencyStateArchiveStep.LoadStoredSlotsToDelete});
|
|
67
83
|
|
|
68
84
|
const statesSlotsToDelete = computeStateSlotsToDelete(storedStateSlots, archiveStateEpochFrequency);
|
|
85
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
69
86
|
if (statesSlotsToDelete.length > 0) {
|
|
70
87
|
await this.db.stateArchive.batchDelete(statesSlotsToDelete);
|
|
71
88
|
}
|
|
89
|
+
timer?.({step: FrequencyStateArchiveStep.DeleteOldStates});
|
|
72
90
|
|
|
73
91
|
// More logs to investigate the rss spike issue https://github.com/ChainSafe/lodestar/issues/5591
|
|
74
92
|
this.logger.verbose("Archived state completed", {
|
|
75
|
-
|
|
93
|
+
...logCtx,
|
|
76
94
|
minEpoch,
|
|
77
95
|
storedStateSlots: storedStateSlots.join(","),
|
|
78
96
|
statesSlotsToDelete: statesSlotsToDelete.join(","),
|
|
79
97
|
});
|
|
98
|
+
} else {
|
|
99
|
+
this.logger.verbose("Skip archiving state", logCtx);
|
|
80
100
|
}
|
|
81
101
|
}
|
|
82
102
|
|
|
@@ -86,24 +106,31 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
86
106
|
*/
|
|
87
107
|
async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise<void> {
|
|
88
108
|
// starting from Mar 2024, the finalized state could be from disk or in memory
|
|
109
|
+
let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
89
110
|
const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized);
|
|
111
|
+
timer?.({step: FrequencyStateArchiveStep.GetFinalizedState});
|
|
112
|
+
|
|
90
113
|
const {rootHex} = finalized;
|
|
91
114
|
if (!finalizedStateOrBytes) {
|
|
92
115
|
throw Error(`No state in cache for finalized checkpoint state epoch #${finalized.epoch} root ${rootHex}`);
|
|
93
116
|
}
|
|
94
117
|
if (finalizedStateOrBytes instanceof Uint8Array) {
|
|
95
118
|
const slot = getStateSlotFromBytes(finalizedStateOrBytes);
|
|
119
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
96
120
|
await this.db.stateArchive.putBinary(slot, finalizedStateOrBytes);
|
|
121
|
+
timer?.({step: FrequencyStateArchiveStep.PersistState});
|
|
97
122
|
this.logger.verbose("Archived finalized state bytes", {epoch: finalized.epoch, slot, root: rootHex});
|
|
98
123
|
} else {
|
|
99
124
|
// serialize state using BufferPool if provided
|
|
100
|
-
const
|
|
125
|
+
const sszTimer = metrics?.stateSerializeDuration.startTimer({source: AllocSource.ARCHIVE_STATE});
|
|
101
126
|
await serializeState(
|
|
102
127
|
finalizedStateOrBytes,
|
|
103
128
|
AllocSource.ARCHIVE_STATE,
|
|
104
|
-
(stateBytes) => {
|
|
105
|
-
|
|
106
|
-
|
|
129
|
+
async (stateBytes) => {
|
|
130
|
+
sszTimer?.();
|
|
131
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
132
|
+
await this.db.stateArchive.putBinary(finalizedStateOrBytes.slot, stateBytes);
|
|
133
|
+
timer?.({step: FrequencyStateArchiveStep.PersistState});
|
|
107
134
|
},
|
|
108
135
|
this.bufferPool
|
|
109
136
|
);
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {Epoch} from "@lodestar/types";
|
|
3
|
-
import {MapDef} from "@lodestar/utils";
|
|
4
3
|
|
|
5
4
|
const PROPOSER_PRESERVE_EPOCHS = 2;
|
|
6
5
|
|
|
7
6
|
export type ProposerPreparationData = routes.validator.ProposerPreparationData;
|
|
8
7
|
|
|
9
8
|
export class BeaconProposerCache {
|
|
10
|
-
private readonly feeRecipientByValidatorIndex:
|
|
11
|
-
constructor(opts: {suggestedFeeRecipient: string}) {
|
|
12
|
-
this.feeRecipientByValidatorIndex = new
|
|
13
|
-
epoch: 0,
|
|
14
|
-
feeRecipient: opts.suggestedFeeRecipient,
|
|
15
|
-
}));
|
|
9
|
+
private readonly feeRecipientByValidatorIndex: Map<number, {epoch: Epoch; feeRecipient: string}>;
|
|
10
|
+
constructor(readonly opts: {suggestedFeeRecipient: string}) {
|
|
11
|
+
this.feeRecipientByValidatorIndex = new Map();
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
add(epoch: Epoch, {validatorIndex, feeRecipient}: ProposerPreparationData): void {
|
|
@@ -30,7 +26,7 @@ export class BeaconProposerCache {
|
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
getOrDefault(proposerIndex: number): string {
|
|
33
|
-
return this.feeRecipientByValidatorIndex.
|
|
29
|
+
return this.feeRecipientByValidatorIndex.get(proposerIndex)?.feeRecipient ?? this.opts.suggestedFeeRecipient;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
get(proposerIndex: number): string | undefined {
|
package/src/chain/chain.ts
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
ValidatorIndex,
|
|
38
38
|
Wei,
|
|
39
39
|
isBlindedBeaconBlock,
|
|
40
|
+
phase0,
|
|
40
41
|
} from "@lodestar/types";
|
|
41
42
|
import {Logger, fromHex, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils";
|
|
42
43
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
@@ -95,11 +96,13 @@ import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js";
|
|
|
95
96
|
import {SeenBlockInput} from "./seenCache/seenGossipBlockInput.js";
|
|
96
97
|
import {ShufflingCache} from "./shufflingCache.js";
|
|
97
98
|
import {BlockStateCacheImpl} from "./stateCache/blockStateCacheImpl.js";
|
|
98
|
-
import {DbCPStateDatastore} from "./stateCache/datastore/db.js";
|
|
99
|
+
import {DbCPStateDatastore, checkpointToDatastoreKey} from "./stateCache/datastore/db.js";
|
|
99
100
|
import {FileCPStateDatastore} from "./stateCache/datastore/file.js";
|
|
101
|
+
import {CPStateDatastore} from "./stateCache/datastore/types.js";
|
|
100
102
|
import {FIFOBlockStateCache} from "./stateCache/fifoBlockStateCache.js";
|
|
101
103
|
import {InMemoryCheckpointStateCache} from "./stateCache/inMemoryCheckpointsCache.js";
|
|
102
104
|
import {PersistentCheckpointStateCache} from "./stateCache/persistentCheckpointsCache.js";
|
|
105
|
+
import {CheckpointStateCache} from "./stateCache/types.js";
|
|
103
106
|
import {ValidatorMonitor} from "./validatorMonitor.js";
|
|
104
107
|
|
|
105
108
|
/**
|
|
@@ -181,6 +184,8 @@ export class BeaconChain implements IBeaconChain {
|
|
|
181
184
|
|
|
182
185
|
protected readonly blockProcessor: BlockProcessor;
|
|
183
186
|
protected readonly db: IBeaconDb;
|
|
187
|
+
// this is only available if nHistoricalStates is enabled
|
|
188
|
+
private readonly cpStateDatastore?: CPStateDatastore;
|
|
184
189
|
private abortController = new AbortController();
|
|
185
190
|
private processShutdownCallback: ProcessShutdownCallback;
|
|
186
191
|
private _earliestAvailableSlot: Slot;
|
|
@@ -210,6 +215,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
210
215
|
metrics,
|
|
211
216
|
validatorMonitor,
|
|
212
217
|
anchorState,
|
|
218
|
+
isAnchorStateFinalized,
|
|
213
219
|
eth1,
|
|
214
220
|
executionEngine,
|
|
215
221
|
executionBuilder,
|
|
@@ -226,6 +232,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
226
232
|
metrics: Metrics | null;
|
|
227
233
|
validatorMonitor: ValidatorMonitor | null;
|
|
228
234
|
anchorState: BeaconStateAllForks;
|
|
235
|
+
isAnchorStateFinalized: boolean;
|
|
229
236
|
eth1: IEth1ForBlockProduction;
|
|
230
237
|
executionEngine: IExecutionEngine;
|
|
231
238
|
executionBuilder?: IExecutionBuilder;
|
|
@@ -257,15 +264,14 @@ export class BeaconChain implements IBeaconChain {
|
|
|
257
264
|
this.attestationPool = new AttestationPool(config, clock, this.opts?.preaggregateSlotDistance, metrics);
|
|
258
265
|
this.aggregatedAttestationPool = new AggregatedAttestationPool(this.config, metrics);
|
|
259
266
|
this.syncCommitteeMessagePool = new SyncCommitteeMessagePool(config, clock, this.opts?.preaggregateSlotDistance);
|
|
260
|
-
this.syncContributionAndProofPool = new SyncContributionAndProofPool(clock, metrics, logger);
|
|
267
|
+
this.syncContributionAndProofPool = new SyncContributionAndProofPool(config, clock, metrics, logger);
|
|
261
268
|
|
|
262
269
|
this.seenAggregatedAttestations = new SeenAggregatedAttestations(metrics);
|
|
263
270
|
this.seenContributionAndProof = new SeenContributionAndProof(metrics);
|
|
264
271
|
this.seenAttestationDatas = new SeenAttestationDatas(metrics, this.opts?.attDataCacheSlotDistance);
|
|
265
272
|
|
|
266
273
|
const nodeId = computeNodeIdFromPrivateKey(privateKey);
|
|
267
|
-
const initialCustodyGroupCount =
|
|
268
|
-
opts.initialCustodyGroupCount ?? (opts.supernode ? config.NUMBER_OF_CUSTODY_GROUPS : config.CUSTODY_REQUIREMENT);
|
|
274
|
+
const initialCustodyGroupCount = opts.initialCustodyGroupCount ?? config.CUSTODY_REQUIREMENT;
|
|
269
275
|
this.metrics?.peerDas.targetCustodyGroupCount.set(initialCustodyGroupCount);
|
|
270
276
|
this.custodyConfig = new CustodyConfig({
|
|
271
277
|
nodeId,
|
|
@@ -326,23 +332,26 @@ export class BeaconChain implements IBeaconChain {
|
|
|
326
332
|
this.bufferPool = this.opts.nHistoricalStates
|
|
327
333
|
? new BufferPool(anchorState.type.tree_serializedSize(anchorState.node), metrics)
|
|
328
334
|
: null;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
335
|
+
|
|
336
|
+
let checkpointStateCache: CheckpointStateCache;
|
|
337
|
+
this.cpStateDatastore = undefined;
|
|
338
|
+
if (this.opts.nHistoricalStates) {
|
|
339
|
+
this.cpStateDatastore = fileDataStore ? new FileCPStateDatastore(dataDir) : new DbCPStateDatastore(this.db);
|
|
340
|
+
checkpointStateCache = new PersistentCheckpointStateCache(
|
|
341
|
+
{
|
|
342
|
+
metrics,
|
|
343
|
+
logger,
|
|
344
|
+
clock,
|
|
345
|
+
blockStateCache,
|
|
346
|
+
bufferPool: this.bufferPool,
|
|
347
|
+
datastore: this.cpStateDatastore,
|
|
348
|
+
},
|
|
349
|
+
this.opts
|
|
350
|
+
);
|
|
351
|
+
} else {
|
|
352
|
+
checkpointStateCache = new InMemoryCheckpointStateCache({metrics});
|
|
353
|
+
}
|
|
354
|
+
|
|
346
355
|
const {checkpoint} = computeAnchorCheckpoint(config, anchorState);
|
|
347
356
|
blockStateCache.add(cachedState);
|
|
348
357
|
blockStateCache.setHeadState(cachedState);
|
|
@@ -353,6 +362,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
353
362
|
emitter,
|
|
354
363
|
clock.currentSlot,
|
|
355
364
|
cachedState,
|
|
365
|
+
isAnchorStateFinalized,
|
|
356
366
|
opts,
|
|
357
367
|
this.justifiedBalancesGetter.bind(this),
|
|
358
368
|
metrics,
|
|
@@ -372,7 +382,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
372
382
|
});
|
|
373
383
|
|
|
374
384
|
if (!opts.disableLightClientServer) {
|
|
375
|
-
this.lightClientServer = new LightClientServer(opts, {config, db, metrics, emitter, logger});
|
|
385
|
+
this.lightClientServer = new LightClientServer(opts, {config, clock, db, metrics, emitter, logger});
|
|
376
386
|
}
|
|
377
387
|
|
|
378
388
|
this.reprocessController = new ReprocessController(this.metrics);
|
|
@@ -604,6 +614,20 @@ export class BeaconChain implements IBeaconChain {
|
|
|
604
614
|
return data && {state: data, executionOptimistic: false, finalized: true};
|
|
605
615
|
}
|
|
606
616
|
|
|
617
|
+
async getPersistedCheckpointState(checkpoint?: phase0.Checkpoint): Promise<Uint8Array | null> {
|
|
618
|
+
if (!this.cpStateDatastore) {
|
|
619
|
+
throw new Error("n-historical-state flag is not enabled");
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (checkpoint == null) {
|
|
623
|
+
// return the last safe checkpoint state by default
|
|
624
|
+
return this.cpStateDatastore.readLatestSafe();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const persistedKey = checkpointToDatastoreKey(checkpoint);
|
|
628
|
+
return this.cpStateDatastore.read(persistedKey);
|
|
629
|
+
}
|
|
630
|
+
|
|
607
631
|
getStateByCheckpoint(
|
|
608
632
|
checkpoint: CheckpointWithHex
|
|
609
633
|
): {state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null {
|
|
@@ -1216,9 +1240,10 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1216
1240
|
}
|
|
1217
1241
|
|
|
1218
1242
|
private async updateValidatorsCustodyRequirement(finalizedCheckpoint: CheckpointWithHex): Promise<void> {
|
|
1219
|
-
if (this.
|
|
1220
|
-
//
|
|
1221
|
-
// of all custody groups
|
|
1243
|
+
if (this.custodyConfig.targetCustodyGroupCount === this.config.NUMBER_OF_CUSTODY_GROUPS) {
|
|
1244
|
+
// Custody requirements can only be increased, we can disable dynamic custody updates
|
|
1245
|
+
// if the node already maintains custody of all custody groups in case it is configured
|
|
1246
|
+
// as a supernode or has validators attached with a total effective balance of at least 4096 ETH.
|
|
1222
1247
|
return;
|
|
1223
1248
|
}
|
|
1224
1249
|
|