@lodestar/beacon-node 1.40.0-dev.0ae7a89ead → 1.40.0-dev.1c71f4299a
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 +8 -18
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +3 -0
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +5 -1
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +3 -6
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +5 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +4 -0
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts +2 -0
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +6 -0
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +2 -6
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +0 -14
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +0 -2
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +0 -7
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts +1 -4
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +20 -28
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +13 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +149 -1
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/interface.d.ts +14 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +2 -0
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +42 -3
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +7 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +24 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +0 -3
- 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 +2 -4
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts +1 -2
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.js +5 -26
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts +1 -2
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +5 -7
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +1 -2
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -5
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +2 -2
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +0 -1
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +0 -3
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +0 -3
- package/lib/sync/unknownBlock.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +8 -18
- package/src/api/impl/config/constants.ts +8 -0
- package/src/api/impl/debug/index.ts +2 -6
- package/src/api/impl/lodestar/index.ts +6 -0
- package/src/chain/archiveStore/utils/archiveBlocks.ts +4 -0
- package/src/chain/blocks/blockInput/blockInput.ts +8 -0
- package/src/chain/blocks/importBlock.ts +2 -6
- package/src/chain/blocks/index.ts +0 -19
- package/src/chain/blocks/types.ts +0 -2
- package/src/chain/blocks/verifyBlock.ts +0 -8
- package/src/chain/blocks/writeBlockInputToDb.ts +24 -30
- package/src/chain/chain.ts +171 -1
- package/src/chain/interface.ts +16 -0
- package/src/chain/validatorMonitor.ts +52 -3
- package/src/metrics/metrics/lodestar.ts +25 -0
- package/src/network/processor/gossipHandlers.ts +0 -3
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +2 -4
- package/src/network/reqresp/handlers/beaconBlocksByRoot.ts +5 -32
- package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +5 -9
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +5 -2
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -5
- package/src/network/reqresp/handlers/index.ts +2 -2
- package/src/sync/range/chain.ts +0 -1
- package/src/sync/range/range.ts +0 -3
- package/src/sync/unknownBlock.ts +0 -3
package/src/chain/chain.ts
CHANGED
|
@@ -37,14 +37,19 @@ import {
|
|
|
37
37
|
UintNum64,
|
|
38
38
|
ValidatorIndex,
|
|
39
39
|
Wei,
|
|
40
|
+
deneb,
|
|
41
|
+
fulu,
|
|
40
42
|
isBlindedBeaconBlock,
|
|
41
43
|
phase0,
|
|
42
44
|
rewards,
|
|
45
|
+
ssz,
|
|
46
|
+
sszTypesFor,
|
|
43
47
|
} from "@lodestar/types";
|
|
44
48
|
import {Logger, fromHex, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils";
|
|
45
49
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
46
50
|
import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js";
|
|
47
51
|
import {IBeaconDb} from "../db/index.js";
|
|
52
|
+
import {BLOB_SIDECARS_IN_WRAPPER_INDEX} from "../db/repositories/blobSidecars.ts";
|
|
48
53
|
import {BuilderStatus} from "../execution/builder/http.js";
|
|
49
54
|
import {IExecutionBuilder, IExecutionEngine} from "../execution/index.js";
|
|
50
55
|
import {Metrics} from "../metrics/index.js";
|
|
@@ -55,12 +60,15 @@ import {CustodyConfig, getValidatorsCustodyRequirement} from "../util/dataColumn
|
|
|
55
60
|
import {callInNextEventLoop} from "../util/eventLoop.js";
|
|
56
61
|
import {ensureDir, writeIfNotExist} from "../util/file.js";
|
|
57
62
|
import {isOptimisticBlock} from "../util/forkChoice.js";
|
|
63
|
+
import {JobItemQueue} from "../util/queue/itemQueue.ts";
|
|
58
64
|
import {SerializedCache} from "../util/serializedCache.js";
|
|
65
|
+
import {getSlotFromSignedBeaconBlockSerialized} from "../util/sszBytes.ts";
|
|
59
66
|
import {ArchiveStore} from "./archiveStore/archiveStore.js";
|
|
60
67
|
import {CheckpointBalancesCache} from "./balancesCache.js";
|
|
61
68
|
import {BeaconProposerCache} from "./beaconProposerCache.js";
|
|
62
|
-
import {IBlockInput} from "./blocks/blockInput/index.js";
|
|
69
|
+
import {IBlockInput, isBlockInputBlobs, isBlockInputColumns} from "./blocks/blockInput/index.js";
|
|
63
70
|
import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js";
|
|
71
|
+
import {persistBlockInputs} from "./blocks/writeBlockInputToDb.ts";
|
|
64
72
|
import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier, IBlsVerifier} from "./bls/index.js";
|
|
65
73
|
import {ColumnReconstructionTracker} from "./ColumnReconstructionTracker.js";
|
|
66
74
|
import {ChainEvent, ChainEventEmitter} from "./emitter.js";
|
|
@@ -113,6 +121,11 @@ import {ValidatorMonitor} from "./validatorMonitor.js";
|
|
|
113
121
|
*/
|
|
114
122
|
const DEFAULT_MAX_CACHED_PRODUCED_RESULTS = 4;
|
|
115
123
|
|
|
124
|
+
/**
|
|
125
|
+
* The maximum number of pending unfinalized block writes to the database before backpressure is applied.
|
|
126
|
+
*/
|
|
127
|
+
const DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES = 32;
|
|
128
|
+
|
|
116
129
|
export class BeaconChain implements IBeaconChain {
|
|
117
130
|
readonly genesisTime: UintNum64;
|
|
118
131
|
readonly genesisValidatorsRoot: Root;
|
|
@@ -136,6 +149,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
136
149
|
readonly lightClientServer?: LightClientServer;
|
|
137
150
|
readonly reprocessController: ReprocessController;
|
|
138
151
|
readonly archiveStore: ArchiveStore;
|
|
152
|
+
readonly unfinalizedBlockWrites: JobItemQueue<[IBlockInput[]], void>;
|
|
139
153
|
|
|
140
154
|
// Ops pool
|
|
141
155
|
readonly attestationPool: AttestationPool;
|
|
@@ -405,6 +419,15 @@ export class BeaconChain implements IBeaconChain {
|
|
|
405
419
|
signal
|
|
406
420
|
);
|
|
407
421
|
|
|
422
|
+
this.unfinalizedBlockWrites = new JobItemQueue(
|
|
423
|
+
persistBlockInputs.bind(this),
|
|
424
|
+
{
|
|
425
|
+
maxLength: DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES,
|
|
426
|
+
signal,
|
|
427
|
+
},
|
|
428
|
+
metrics?.unfinalizedBlockWritesQueue
|
|
429
|
+
);
|
|
430
|
+
|
|
408
431
|
// always run PrepareNextSlotScheduler except for fork_choice spec tests
|
|
409
432
|
if (!opts?.disablePrepareNextSlot) {
|
|
410
433
|
new PrepareNextSlotScheduler(this, this.config, metrics, this.logger, signal);
|
|
@@ -430,6 +453,12 @@ export class BeaconChain implements IBeaconChain {
|
|
|
430
453
|
async close(): Promise<void> {
|
|
431
454
|
await this.archiveStore.close();
|
|
432
455
|
await this.bls.close();
|
|
456
|
+
|
|
457
|
+
// Since we don't persist unfinalized fork-choice,
|
|
458
|
+
// we can abort any ongoing unfinalized block writes.
|
|
459
|
+
// TODO: persist fork choice to disk and allow unfinalized block writes to complete.
|
|
460
|
+
this.unfinalizedBlockWrites.dropAllJobs();
|
|
461
|
+
|
|
433
462
|
this.abortController.abort();
|
|
434
463
|
}
|
|
435
464
|
|
|
@@ -652,6 +681,13 @@ export class BeaconChain implements IBeaconChain {
|
|
|
652
681
|
// Unfinalized slot, attempt to find in fork-choice
|
|
653
682
|
const block = this.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
654
683
|
if (block) {
|
|
684
|
+
// Block found in fork-choice.
|
|
685
|
+
// It may be in the block input cache, awaiting full DA reconstruction, check there first
|
|
686
|
+
// Otherwise (most likely), check the hot db
|
|
687
|
+
const blockInput = this.seenBlockInputCache.get(block.blockRoot);
|
|
688
|
+
if (blockInput?.hasBlock()) {
|
|
689
|
+
return {block: blockInput.getBlock(), executionOptimistic: isOptimisticBlock(block), finalized: false};
|
|
690
|
+
}
|
|
655
691
|
const data = await this.db.block.get(fromHex(block.blockRoot));
|
|
656
692
|
if (data) {
|
|
657
693
|
return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false};
|
|
@@ -671,6 +707,13 @@ export class BeaconChain implements IBeaconChain {
|
|
|
671
707
|
): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null> {
|
|
672
708
|
const block = this.forkChoice.getBlockHex(root);
|
|
673
709
|
if (block) {
|
|
710
|
+
// Block found in fork-choice.
|
|
711
|
+
// It may be in the block input cache, awaiting full DA reconstruction, check there first
|
|
712
|
+
// Otherwise (most likely), check the hot db
|
|
713
|
+
const blockInput = this.seenBlockInputCache.get(block.blockRoot);
|
|
714
|
+
if (blockInput?.hasBlock()) {
|
|
715
|
+
return {block: blockInput.getBlock(), executionOptimistic: isOptimisticBlock(block), finalized: false};
|
|
716
|
+
}
|
|
674
717
|
const data = await this.db.block.get(fromHex(root));
|
|
675
718
|
if (data) {
|
|
676
719
|
return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false};
|
|
@@ -683,6 +726,133 @@ export class BeaconChain implements IBeaconChain {
|
|
|
683
726
|
return data && {block: data, executionOptimistic: false, finalized: true};
|
|
684
727
|
}
|
|
685
728
|
|
|
729
|
+
async getSerializedBlockByRoot(
|
|
730
|
+
root: string
|
|
731
|
+
): Promise<{block: Uint8Array; executionOptimistic: boolean; finalized: boolean; slot: Slot} | null> {
|
|
732
|
+
const block = this.forkChoice.getBlockHex(root);
|
|
733
|
+
if (block) {
|
|
734
|
+
// Block found in fork-choice.
|
|
735
|
+
// It may be in the block input cache, awaiting full DA reconstruction, check there first
|
|
736
|
+
// Otherwise (most likely), check the hot db
|
|
737
|
+
const blockInput = this.seenBlockInputCache.get(block.blockRoot);
|
|
738
|
+
if (blockInput?.hasBlock()) {
|
|
739
|
+
const signedBlock = blockInput.getBlock();
|
|
740
|
+
const serialized = this.serializedCache.get(signedBlock);
|
|
741
|
+
if (serialized) {
|
|
742
|
+
return {
|
|
743
|
+
block: serialized,
|
|
744
|
+
executionOptimistic: isOptimisticBlock(block),
|
|
745
|
+
finalized: false,
|
|
746
|
+
slot: blockInput.slot,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
return {
|
|
750
|
+
block: sszTypesFor(blockInput.forkName).SignedBeaconBlock.serialize(signedBlock),
|
|
751
|
+
executionOptimistic: isOptimisticBlock(block),
|
|
752
|
+
finalized: false,
|
|
753
|
+
slot: blockInput.slot,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
const data = await this.db.block.getBinary(fromHex(root));
|
|
757
|
+
if (data) {
|
|
758
|
+
const slot = getSlotFromSignedBeaconBlockSerialized(data);
|
|
759
|
+
if (slot === null) throw new Error(`Invalid block data stored in DB for root: ${root}`);
|
|
760
|
+
return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false, slot};
|
|
761
|
+
}
|
|
762
|
+
// If block is not found in hot db, try cold db since there could be an archive cycle happening
|
|
763
|
+
// TODO: Add a lock to the archiver to have deterministic behavior on where are blocks
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const data = await this.db.blockArchive.getBinaryEntryByRoot(fromHex(root));
|
|
767
|
+
return data && {block: data.value, executionOptimistic: false, finalized: true, slot: data.key};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
async getBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<deneb.BlobSidecars | null> {
|
|
771
|
+
const blockInput = this.seenBlockInputCache.get(blockRootHex);
|
|
772
|
+
if (blockInput) {
|
|
773
|
+
if (!isBlockInputBlobs(blockInput)) {
|
|
774
|
+
throw new Error(`Expected block input to have blobs: slot=${blockSlot} root=${blockRootHex}`);
|
|
775
|
+
}
|
|
776
|
+
if (!blockInput.hasAllData()) {
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
return blockInput.getBlobs();
|
|
780
|
+
}
|
|
781
|
+
const unfinalizedBlobSidecars = (await this.db.blobSidecars.get(fromHex(blockRootHex)))?.blobSidecars ?? null;
|
|
782
|
+
if (unfinalizedBlobSidecars) {
|
|
783
|
+
return unfinalizedBlobSidecars;
|
|
784
|
+
}
|
|
785
|
+
return (await this.db.blobSidecarsArchive.get(blockSlot))?.blobSidecars ?? null;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
async getSerializedBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null> {
|
|
789
|
+
const blockInput = this.seenBlockInputCache.get(blockRootHex);
|
|
790
|
+
if (blockInput) {
|
|
791
|
+
if (!isBlockInputBlobs(blockInput)) {
|
|
792
|
+
throw new Error(`Expected block input to have blobs: slot=${blockSlot} root=${blockRootHex}`);
|
|
793
|
+
}
|
|
794
|
+
if (!blockInput.hasAllData()) {
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
return ssz.deneb.BlobSidecars.serialize(blockInput.getBlobs());
|
|
798
|
+
}
|
|
799
|
+
const unfinalizedBlobSidecarsWrapper = await this.db.blobSidecars.getBinary(fromHex(blockRootHex));
|
|
800
|
+
if (unfinalizedBlobSidecarsWrapper) {
|
|
801
|
+
return unfinalizedBlobSidecarsWrapper.slice(BLOB_SIDECARS_IN_WRAPPER_INDEX);
|
|
802
|
+
}
|
|
803
|
+
const finalizedBlobSidecarsWrapper = await this.db.blobSidecarsArchive.getBinary(blockSlot);
|
|
804
|
+
if (finalizedBlobSidecarsWrapper) {
|
|
805
|
+
return finalizedBlobSidecarsWrapper.slice(BLOB_SIDECARS_IN_WRAPPER_INDEX);
|
|
806
|
+
}
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<fulu.DataColumnSidecars> {
|
|
811
|
+
const blockInput = this.seenBlockInputCache.get(blockRootHex);
|
|
812
|
+
if (blockInput) {
|
|
813
|
+
if (!isBlockInputColumns(blockInput)) {
|
|
814
|
+
throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
|
|
815
|
+
}
|
|
816
|
+
return blockInput.getAllColumns();
|
|
817
|
+
}
|
|
818
|
+
const sidecarsUnfinalized = await this.db.dataColumnSidecar.values(fromHex(blockRootHex));
|
|
819
|
+
if (sidecarsUnfinalized.length > 0) {
|
|
820
|
+
return sidecarsUnfinalized;
|
|
821
|
+
}
|
|
822
|
+
const sidecarsFinalized = await this.db.dataColumnSidecarArchive.values(blockSlot);
|
|
823
|
+
return sidecarsFinalized;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
async getSerializedDataColumnSidecars(
|
|
827
|
+
blockSlot: Slot,
|
|
828
|
+
blockRootHex: string,
|
|
829
|
+
indices: number[]
|
|
830
|
+
): Promise<(Uint8Array | undefined)[]> {
|
|
831
|
+
const blockInput = this.seenBlockInputCache.get(blockRootHex);
|
|
832
|
+
if (blockInput) {
|
|
833
|
+
if (!isBlockInputColumns(blockInput)) {
|
|
834
|
+
throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
|
|
835
|
+
}
|
|
836
|
+
return indices.map((index) => {
|
|
837
|
+
const sidecar = blockInput.getColumn(index);
|
|
838
|
+
if (!sidecar) {
|
|
839
|
+
return undefined;
|
|
840
|
+
}
|
|
841
|
+
const serialized = this.serializedCache.get(sidecar);
|
|
842
|
+
if (serialized) {
|
|
843
|
+
return serialized;
|
|
844
|
+
}
|
|
845
|
+
return ssz.fulu.DataColumnSidecar.serialize(sidecar);
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
const sidecarsUnfinalized = await this.db.dataColumnSidecar.getManyBinary(fromHex(blockRootHex), indices);
|
|
849
|
+
if (sidecarsUnfinalized.some((sidecar) => sidecar != null)) {
|
|
850
|
+
return sidecarsUnfinalized;
|
|
851
|
+
}
|
|
852
|
+
const sidecarsFinalized = await this.db.dataColumnSidecarArchive.getManyBinary(blockSlot, indices);
|
|
853
|
+
return sidecarsFinalized;
|
|
854
|
+
}
|
|
855
|
+
|
|
686
856
|
async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody> {
|
|
687
857
|
const {slot, parentBlockRoot} = blockAttributes;
|
|
688
858
|
const state = await this.regen.getBlockSlotState(
|
package/src/chain/interface.ts
CHANGED
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
Wei,
|
|
23
23
|
altair,
|
|
24
24
|
capella,
|
|
25
|
+
deneb,
|
|
26
|
+
fulu,
|
|
25
27
|
phase0,
|
|
26
28
|
rewards,
|
|
27
29
|
} from "@lodestar/types";
|
|
@@ -193,12 +195,26 @@ export interface IBeaconChain {
|
|
|
193
195
|
getCanonicalBlockAtSlot(
|
|
194
196
|
slot: Slot
|
|
195
197
|
): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null>;
|
|
198
|
+
/**
|
|
199
|
+
* Get local block by root, does not fetch from the network
|
|
200
|
+
*/
|
|
201
|
+
getSerializedBlockByRoot(
|
|
202
|
+
root: RootHex
|
|
203
|
+
): Promise<{block: Uint8Array; executionOptimistic: boolean; finalized: boolean; slot: Slot} | null>;
|
|
196
204
|
/**
|
|
197
205
|
* Get local block by root, does not fetch from the network
|
|
198
206
|
*/
|
|
199
207
|
getBlockByRoot(
|
|
200
208
|
root: RootHex
|
|
201
209
|
): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null>;
|
|
210
|
+
getBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<deneb.BlobSidecars | null>;
|
|
211
|
+
getSerializedBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null>;
|
|
212
|
+
getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<fulu.DataColumnSidecars>;
|
|
213
|
+
getSerializedDataColumnSidecars(
|
|
214
|
+
blockSlot: Slot,
|
|
215
|
+
blockRootHex: string,
|
|
216
|
+
indices: number[]
|
|
217
|
+
): Promise<(Uint8Array | undefined)[]>;
|
|
202
218
|
|
|
203
219
|
produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
|
|
204
220
|
produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
altair,
|
|
25
25
|
deneb,
|
|
26
26
|
} from "@lodestar/types";
|
|
27
|
-
import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, toRootHex} from "@lodestar/utils";
|
|
27
|
+
import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
28
28
|
import {GENESIS_SLOT} from "../constants/constants.js";
|
|
29
29
|
import {RegistryMetricCreator} from "../metrics/index.js";
|
|
30
30
|
|
|
@@ -39,7 +39,8 @@ const MAX_CACHED_DISTINCT_TARGETS = 4;
|
|
|
39
39
|
const LATE_ATTESTATION_SUBMISSION_BPS = 5000;
|
|
40
40
|
const LATE_BLOCK_SUBMISSION_BPS = 2500;
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
/** Number of epochs to retain registered validators after their last registration */
|
|
43
|
+
const RETAIN_REGISTERED_VALIDATORS_EPOCHS = 2;
|
|
43
44
|
|
|
44
45
|
type Seconds = number;
|
|
45
46
|
export enum OpSource {
|
|
@@ -97,6 +98,8 @@ export type ValidatorMonitor = {
|
|
|
97
98
|
): void;
|
|
98
99
|
onceEveryEndOfEpoch(state: CachedBeaconStateAllForks): void;
|
|
99
100
|
scrapeMetrics(slotClock: Slot): void;
|
|
101
|
+
/** Returns the list of validator indices currently being monitored */
|
|
102
|
+
getMonitoredValidatorIndices(): ValidatorIndex[];
|
|
100
103
|
};
|
|
101
104
|
|
|
102
105
|
export type ValidatorMonitorOpts = {
|
|
@@ -284,6 +287,9 @@ export function createValidatorMonitor(
|
|
|
284
287
|
logger[logLevel](message, context);
|
|
285
288
|
};
|
|
286
289
|
|
|
290
|
+
// Calculate retain time dynamically based on slot duration (2 epochs)
|
|
291
|
+
const retainRegisteredValidatorsMs = SLOTS_PER_EPOCH * config.SLOT_DURATION_MS * RETAIN_REGISTERED_VALIDATORS_EPOCHS;
|
|
292
|
+
|
|
287
293
|
/** The validators that require additional monitoring. */
|
|
288
294
|
const validators = new MapDef<ValidatorIndex, MonitoredValidator>(() => ({
|
|
289
295
|
summaries: new Map<Epoch, EpochSummary>(),
|
|
@@ -306,11 +312,19 @@ export function createValidatorMonitor(
|
|
|
306
312
|
|
|
307
313
|
let lastRegisteredStatusEpoch = -1;
|
|
308
314
|
|
|
315
|
+
// Track validator additions/removals per epoch for logging
|
|
316
|
+
const addedValidatorsInEpoch: Set<ValidatorIndex> = new Set();
|
|
317
|
+
const removedValidatorsInEpoch: Set<ValidatorIndex> = new Set();
|
|
318
|
+
|
|
309
319
|
const validatorMonitorMetrics = metricsRegister ? createValidatorMonitorMetrics(metricsRegister) : null;
|
|
310
320
|
|
|
311
321
|
const validatorMonitor: ValidatorMonitor = {
|
|
312
322
|
registerLocalValidator(index) {
|
|
323
|
+
const isNewValidator = !validators.has(index);
|
|
313
324
|
validators.getOrDefault(index).lastRegisteredTimeMs = Date.now();
|
|
325
|
+
if (isNewValidator) {
|
|
326
|
+
addedValidatorsInEpoch.add(index);
|
|
327
|
+
}
|
|
314
328
|
},
|
|
315
329
|
|
|
316
330
|
registerLocalValidatorInSyncCommittee(index, untilEpoch) {
|
|
@@ -673,11 +687,29 @@ export function createValidatorMonitor(
|
|
|
673
687
|
|
|
674
688
|
// Prune validators not seen in a while
|
|
675
689
|
for (const [index, validator] of validators.entries()) {
|
|
676
|
-
if (Date.now() - validator.lastRegisteredTimeMs >
|
|
690
|
+
if (Date.now() - validator.lastRegisteredTimeMs > retainRegisteredValidatorsMs) {
|
|
677
691
|
validators.delete(index);
|
|
692
|
+
removedValidatorsInEpoch.add(index);
|
|
678
693
|
}
|
|
679
694
|
}
|
|
680
695
|
|
|
696
|
+
// Log validator monitor status every epoch
|
|
697
|
+
const allIndices = Array.from(validators.keys()).sort((a, b) => a - b);
|
|
698
|
+
const addedIndices = Array.from(addedValidatorsInEpoch).sort((a, b) => a - b);
|
|
699
|
+
const removedIndices = Array.from(removedValidatorsInEpoch).sort((a, b) => a - b);
|
|
700
|
+
|
|
701
|
+
log("Validator monitor status", {
|
|
702
|
+
epoch: computeEpochAtSlot(headState.slot),
|
|
703
|
+
added: addedIndices.length > 0 ? prettyPrintIndices(addedIndices) : "none",
|
|
704
|
+
removed: removedIndices.length > 0 ? prettyPrintIndices(removedIndices) : "none",
|
|
705
|
+
total: validators.size,
|
|
706
|
+
indices: prettyPrintIndices(allIndices),
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
// Clear tracking sets for next epoch
|
|
710
|
+
addedValidatorsInEpoch.clear();
|
|
711
|
+
removedValidatorsInEpoch.clear();
|
|
712
|
+
|
|
681
713
|
// Compute summaries of previous epoch attestation performance
|
|
682
714
|
const prevEpoch = computeEpochAtSlot(headState.slot) - 1;
|
|
683
715
|
|
|
@@ -736,6 +768,13 @@ export function createValidatorMonitor(
|
|
|
736
768
|
scrapeMetrics(slotClock) {
|
|
737
769
|
validatorMonitorMetrics?.validatorsConnected.set(validators.size);
|
|
738
770
|
|
|
771
|
+
// Update static metric with connected validator indices
|
|
772
|
+
if (validatorMonitorMetrics?.validatorsConnectedIndices) {
|
|
773
|
+
validatorMonitorMetrics.validatorsConnectedIndices.reset();
|
|
774
|
+
const allIndices = Array.from(validators.keys()).sort((a, b) => a - b);
|
|
775
|
+
validatorMonitorMetrics.validatorsConnectedIndices.set({indices: prettyPrintIndices(allIndices)}, 1);
|
|
776
|
+
}
|
|
777
|
+
|
|
739
778
|
const epoch = computeEpochAtSlot(slotClock);
|
|
740
779
|
const slotInEpoch = slotClock % SLOTS_PER_EPOCH;
|
|
741
780
|
|
|
@@ -815,6 +854,10 @@ export function createValidatorMonitor(
|
|
|
815
854
|
validatorMonitorMetrics?.prevEpochSyncCommitteeHits.set(prevEpochSyncCommitteeHits);
|
|
816
855
|
validatorMonitorMetrics?.prevEpochSyncCommitteeMisses.set(prevEpochSyncCommitteeMisses);
|
|
817
856
|
},
|
|
857
|
+
|
|
858
|
+
getMonitoredValidatorIndices() {
|
|
859
|
+
return Array.from(validators.keys()).sort((a, b) => a - b);
|
|
860
|
+
},
|
|
818
861
|
};
|
|
819
862
|
|
|
820
863
|
// Register a single collect() function to run all validatorMonitor metrics
|
|
@@ -1098,6 +1141,12 @@ function createValidatorMonitorMetrics(register: RegistryMetricCreator) {
|
|
|
1098
1141
|
help: "Count of validators that are specifically monitored by this beacon node",
|
|
1099
1142
|
}),
|
|
1100
1143
|
|
|
1144
|
+
validatorsConnectedIndices: register.gauge<{indices: string}>({
|
|
1145
|
+
name: "validator_monitor_indices",
|
|
1146
|
+
help: "Static metric with connected validator indices as label, value is always 1",
|
|
1147
|
+
labelNames: ["indices"],
|
|
1148
|
+
}),
|
|
1149
|
+
|
|
1101
1150
|
validatorsInSyncCommittee: register.gauge({
|
|
1102
1151
|
name: "validator_monitor_validators_in_sync_committee",
|
|
1103
1152
|
help: "Count of validators monitored by this beacon node that are part of sync committee",
|
|
@@ -212,6 +212,31 @@ export function createLodestarMetrics(
|
|
|
212
212
|
}),
|
|
213
213
|
},
|
|
214
214
|
|
|
215
|
+
unfinalizedBlockWritesQueue: {
|
|
216
|
+
length: register.gauge({
|
|
217
|
+
name: "lodestar_unfinalized_block_writes_queue_length",
|
|
218
|
+
help: "Count of total unfinalized block writes queue length",
|
|
219
|
+
}),
|
|
220
|
+
droppedJobs: register.gauge({
|
|
221
|
+
name: "lodestar_unfinalized_block_writes_queue_dropped_jobs_total",
|
|
222
|
+
help: "Count of total unfinalized block writes queue dropped jobs",
|
|
223
|
+
}),
|
|
224
|
+
jobTime: register.histogram({
|
|
225
|
+
name: "lodestar_unfinalized_block_writes_queue_job_time_seconds",
|
|
226
|
+
help: "Time to process unfinalized block writes queue job in seconds",
|
|
227
|
+
buckets: [0.01, 0.1, 1, 4, 12],
|
|
228
|
+
}),
|
|
229
|
+
jobWaitTime: register.histogram({
|
|
230
|
+
name: "lodestar_unfinalized_block_writes_queue_job_wait_time_seconds",
|
|
231
|
+
help: "Time from job added to the unfinalized block writes queue to starting in seconds",
|
|
232
|
+
buckets: [0.01, 0.1, 1, 4, 12],
|
|
233
|
+
}),
|
|
234
|
+
concurrency: register.gauge({
|
|
235
|
+
name: "lodestar_unfinalized_block_writes_queue_concurrency",
|
|
236
|
+
help: "Current concurrency of unfinalized block writes queue",
|
|
237
|
+
}),
|
|
238
|
+
},
|
|
239
|
+
|
|
215
240
|
engineHttpProcessorQueue: {
|
|
216
241
|
length: register.gauge({
|
|
217
242
|
name: "lodestar_engine_http_processor_queue_length",
|
|
@@ -436,14 +436,11 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
436
436
|
blsVerifyOnMainThread: true,
|
|
437
437
|
// to track block process steps
|
|
438
438
|
seenTimestampSec,
|
|
439
|
-
// gossip block is validated, we want to process it asap
|
|
440
|
-
eagerPersistBlock: true,
|
|
441
439
|
})
|
|
442
440
|
.then(() => {
|
|
443
441
|
// Returns the delay between the start of `block.slot` and `current time`
|
|
444
442
|
const delaySec = chain.clock.secFromSlot(slot);
|
|
445
443
|
metrics?.gossipBlock.elapsedTimeTillProcessed.observe(delaySec);
|
|
446
|
-
chain.seenBlockInputCache.prune(blockInput.blockRootHex);
|
|
447
444
|
})
|
|
448
445
|
.catch((e) => {
|
|
449
446
|
// Adjust verbosity based on error type
|
|
@@ -4,7 +4,6 @@ import {GENESIS_SLOT, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
|
|
|
4
4
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
5
5
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
6
6
|
import {deneb, phase0} from "@lodestar/types";
|
|
7
|
-
import {fromHex} from "@lodestar/utils";
|
|
8
7
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
9
8
|
import {IBeaconDb} from "../../../db/index.js";
|
|
10
9
|
import {prettyPrintPeerId} from "../../util.ts";
|
|
@@ -22,7 +21,6 @@ export async function* onBeaconBlocksByRange(
|
|
|
22
21
|
const endSlot = startSlot + count;
|
|
23
22
|
|
|
24
23
|
const finalized = db.blockArchive;
|
|
25
|
-
const unfinalized = db.block;
|
|
26
24
|
// in the case of initializing from a non-finalized state, we don't have the finalized block so this api does not work
|
|
27
25
|
// chain.forkChoice.getFinalizeBlock().slot
|
|
28
26
|
const finalizedSlot = chain.forkChoice.getFinalizedCheckpointSlot();
|
|
@@ -65,7 +63,7 @@ export async function* onBeaconBlocksByRange(
|
|
|
65
63
|
// re-org there's no need to abort the request
|
|
66
64
|
// Spec: https://github.com/ethereum/consensus-specs/blob/a1e46d1ae47dd9d097725801575b46907c12a1f8/specs/eip4844/p2p-interface.md#blobssidecarsbyrange-v1
|
|
67
65
|
|
|
68
|
-
const blockBytes = await
|
|
66
|
+
const blockBytes = await chain.getSerializedBlockByRoot(block.blockRoot);
|
|
69
67
|
if (!blockBytes) {
|
|
70
68
|
throw new ResponseError(
|
|
71
69
|
RespStatus.SERVER_ERROR,
|
|
@@ -74,7 +72,7 @@ export async function* onBeaconBlocksByRange(
|
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
yield {
|
|
77
|
-
data: blockBytes,
|
|
75
|
+
data: blockBytes.block,
|
|
78
76
|
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(block.slot)),
|
|
79
77
|
};
|
|
80
78
|
}
|
|
@@ -1,48 +1,21 @@
|
|
|
1
1
|
import {ResponseOutgoing} from "@lodestar/reqresp";
|
|
2
2
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
3
|
-
import {Slot} from "@lodestar/types";
|
|
4
3
|
import {toRootHex} from "@lodestar/utils";
|
|
5
4
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
6
|
-
import {IBeaconDb} from "../../../db/index.js";
|
|
7
|
-
import {getSlotFromSignedBeaconBlockSerialized} from "../../../util/sszBytes.js";
|
|
8
5
|
import {BeaconBlocksByRootRequest} from "../../../util/types.js";
|
|
9
6
|
|
|
10
7
|
export async function* onBeaconBlocksByRoot(
|
|
11
8
|
requestBody: BeaconBlocksByRootRequest,
|
|
12
|
-
chain: IBeaconChain
|
|
13
|
-
db: IBeaconDb
|
|
9
|
+
chain: IBeaconChain
|
|
14
10
|
): AsyncIterable<ResponseOutgoing> {
|
|
15
11
|
for (const blockRoot of requestBody) {
|
|
16
12
|
const root = blockRoot;
|
|
17
|
-
const
|
|
18
|
-
let blockBytes: Uint8Array | null = null;
|
|
19
|
-
|
|
20
|
-
// finalized block has summary in forkchoice but it stays in blockArchive db
|
|
21
|
-
if (summary) {
|
|
22
|
-
blockBytes = await db.block.getBinary(root);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
let slot: Slot | undefined = undefined;
|
|
26
|
-
if (!blockBytes) {
|
|
27
|
-
const blockEntry = await db.blockArchive.getBinaryEntryByRoot(root);
|
|
28
|
-
if (blockEntry) {
|
|
29
|
-
slot = blockEntry.key;
|
|
30
|
-
blockBytes = blockEntry.value;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (blockBytes) {
|
|
35
|
-
if (slot === undefined) {
|
|
36
|
-
const slotFromBytes = getSlotFromSignedBeaconBlockSerialized(blockBytes);
|
|
37
|
-
if (slotFromBytes === null) {
|
|
38
|
-
throw Error(`Invalid block bytes for block root ${toRootHex(root)}`);
|
|
39
|
-
}
|
|
40
|
-
slot = slotFromBytes;
|
|
41
|
-
}
|
|
13
|
+
const block = await chain.getSerializedBlockByRoot(toRootHex(root));
|
|
42
14
|
|
|
15
|
+
if (block) {
|
|
43
16
|
yield {
|
|
44
|
-
data:
|
|
45
|
-
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(slot)),
|
|
17
|
+
data: block.block,
|
|
18
|
+
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(block.slot)),
|
|
46
19
|
};
|
|
47
20
|
}
|
|
48
21
|
}
|
|
@@ -2,16 +2,13 @@ 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";
|
|
5
|
-
import {
|
|
5
|
+
import {toRootHex} from "@lodestar/utils";
|
|
6
6
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
7
|
-
import {IBeaconDb} from "../../../db/index.js";
|
|
8
|
-
import {BLOB_SIDECARS_IN_WRAPPER_INDEX} from "../../../db/repositories/blobSidecars.js";
|
|
9
7
|
import {BlobSidecarsByRootRequest} from "../../../util/types.js";
|
|
10
8
|
|
|
11
9
|
export async function* onBlobSidecarsByRoot(
|
|
12
10
|
requestBody: BlobSidecarsByRootRequest,
|
|
13
|
-
chain: IBeaconChain
|
|
14
|
-
db: IBeaconDb
|
|
11
|
+
chain: IBeaconChain
|
|
15
12
|
): AsyncIterable<ResponseOutgoing> {
|
|
16
13
|
const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot;
|
|
17
14
|
|
|
@@ -34,14 +31,13 @@ export async function* onBlobSidecarsByRoot(
|
|
|
34
31
|
|
|
35
32
|
// Check if we need to load sidecars for a new block root
|
|
36
33
|
if (lastFetchedSideCars === null || lastFetchedSideCars.blockRoot !== blockRootHex) {
|
|
37
|
-
const
|
|
38
|
-
if (!
|
|
34
|
+
const blobSidecarsBytes = await chain.getSerializedBlobSidecars(block.slot, blockRootHex);
|
|
35
|
+
if (!blobSidecarsBytes) {
|
|
39
36
|
// Handle the same to onBeaconBlocksByRange
|
|
40
37
|
throw new ResponseError(RespStatus.SERVER_ERROR, `No item for root ${block.blockRoot} slot ${block.slot}`);
|
|
41
38
|
}
|
|
42
|
-
const blobSideCarsBytes = blobSideCarsBytesWrapped.slice(BLOB_SIDECARS_IN_WRAPPER_INDEX);
|
|
43
39
|
|
|
44
|
-
lastFetchedSideCars = {blockRoot: blockRootHex, bytes:
|
|
40
|
+
lastFetchedSideCars = {blockRoot: blockRootHex, bytes: blobSidecarsBytes};
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
const blobSidecarBytes = lastFetchedSideCars.bytes.slice(
|
|
@@ -38,7 +38,6 @@ export async function* onDataColumnSidecarsByRange(
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const finalized = db.dataColumnSidecarArchive;
|
|
41
|
-
const unfinalized = db.dataColumnSidecar;
|
|
42
41
|
const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot;
|
|
43
42
|
|
|
44
43
|
// Finalized range of columns
|
|
@@ -92,7 +91,11 @@ export async function* onDataColumnSidecarsByRange(
|
|
|
92
91
|
// at the time of the start of the request. Spec is clear the chain of columns must be consistent, but on
|
|
93
92
|
// re-org there's no need to abort the request
|
|
94
93
|
// Spec: https://github.com/ethereum/consensus-specs/blob/ad36024441cf910d428d03f87f331fbbd2b3e5f1/specs/fulu/p2p-interface.md#L425-L429
|
|
95
|
-
const dataColumnSidecars = await
|
|
94
|
+
const dataColumnSidecars = await chain.getSerializedDataColumnSidecars(
|
|
95
|
+
block.slot,
|
|
96
|
+
block.blockRoot,
|
|
97
|
+
availableColumns
|
|
98
|
+
);
|
|
96
99
|
|
|
97
100
|
const unavailableColumnIndices: ColumnIndex[] = [];
|
|
98
101
|
for (let i = 0; i < dataColumnSidecars.length; i++) {
|
|
@@ -61,11 +61,7 @@ export async function* onDataColumnSidecarsByRoot(
|
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const dataColumns =
|
|
65
|
-
? // Non-finalized sidecars are stored by block root
|
|
66
|
-
await db.dataColumnSidecar.getManyBinary(blockRoot, availableColumns)
|
|
67
|
-
: // Finalized sidecars are archived and stored by slot
|
|
68
|
-
await db.dataColumnSidecarArchive.getManyBinary(slot, availableColumns);
|
|
64
|
+
const dataColumns = await chain.getSerializedDataColumnSidecars(slot, blockRootHex, availableColumns);
|
|
69
65
|
|
|
70
66
|
const unavailableColumnIndices: ColumnIndex[] = [];
|
|
71
67
|
for (let i = 0; i < dataColumns.length; i++) {
|
|
@@ -42,12 +42,12 @@ export function getReqRespHandlers({db, chain}: {db: IBeaconDb; chain: IBeaconCh
|
|
|
42
42
|
[ReqRespMethod.BeaconBlocksByRoot]: (req) => {
|
|
43
43
|
const fork = chain.config.getForkName(chain.clock.currentSlot);
|
|
44
44
|
const body = BeaconBlocksByRootRequestType(fork, chain.config).deserialize(req.data);
|
|
45
|
-
return onBeaconBlocksByRoot(body, chain
|
|
45
|
+
return onBeaconBlocksByRoot(body, chain);
|
|
46
46
|
},
|
|
47
47
|
[ReqRespMethod.BlobSidecarsByRoot]: (req) => {
|
|
48
48
|
const fork = chain.config.getForkName(chain.clock.currentSlot);
|
|
49
49
|
const body = BlobSidecarsByRootRequestType(fork, chain.config).deserialize(req.data);
|
|
50
|
-
return onBlobSidecarsByRoot(body, chain
|
|
50
|
+
return onBlobSidecarsByRoot(body, chain);
|
|
51
51
|
},
|
|
52
52
|
[ReqRespMethod.BlobSidecarsByRange]: (req) => {
|
|
53
53
|
const body = ssz.deneb.BlobSidecarsByRangeRequest.deserialize(req.data);
|
package/src/sync/range/chain.ts
CHANGED
package/src/sync/range/range.ts
CHANGED
|
@@ -188,9 +188,6 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
188
188
|
// when this runs, syncing is the most important thing and gossip is not likely to run
|
|
189
189
|
// so we can utilize worker threads to verify signatures
|
|
190
190
|
blsVerifyOnMainThread: false,
|
|
191
|
-
// we want to be safe to only persist blocks after verifying it to avoid any attacks that may cause our DB
|
|
192
|
-
// to grow too much
|
|
193
|
-
eagerPersistBlock: false,
|
|
194
191
|
};
|
|
195
192
|
|
|
196
193
|
if (this.opts?.disableProcessAsChainSegment) {
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -423,8 +423,6 @@ export class BlockInputSync {
|
|
|
423
423
|
// see https://github.com/ChainSafe/lodestar/issues/5650
|
|
424
424
|
ignoreIfFinalized: true,
|
|
425
425
|
blsVerifyOnMainThread: true,
|
|
426
|
-
// block is validated with correct root, we want to process it as soon as possible
|
|
427
|
-
eagerPersistBlock: true,
|
|
428
426
|
})
|
|
429
427
|
);
|
|
430
428
|
|
|
@@ -434,7 +432,6 @@ export class BlockInputSync {
|
|
|
434
432
|
if (!res.err) {
|
|
435
433
|
// no need to update status to "processed", delete anyway
|
|
436
434
|
this.pendingBlocks.delete(pendingBlock.blockInput.blockRootHex);
|
|
437
|
-
this.chain.seenBlockInputCache.prune(pendingBlock.blockInput.blockRootHex);
|
|
438
435
|
|
|
439
436
|
// Send child blocks to the processor
|
|
440
437
|
for (const descendantBlock of getDescendantBlocks(pendingBlock.blockInput.blockRootHex, this.pendingBlocks)) {
|