@lodestar/beacon-node 1.35.0-dev.ba92bd8a88 → 1.35.0-dev.be3c5220f4
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 -2
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +24 -33
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +3 -2
- 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 +7 -6
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
- package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +1 -7
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +4 -6
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts +2 -2
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +2 -0
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/attestationPool.d.ts +2 -3
- package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/attestationPool.js +3 -5
- package/lib/chain/opPools/attestationPool.js.map +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.d.ts +3 -2
- package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.js +6 -5
- package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
- package/lib/chain/opPools/types.d.ts +1 -1
- package/lib/chain/opPools/types.d.ts.map +1 -1
- package/lib/chain/opPools/types.js +1 -1
- package/lib/chain/opPools/types.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts +3 -3
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +8 -8
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +1 -4
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +13 -4
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +1 -0
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +1 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js +8 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +9 -8
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +1 -1
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/lightClientFinalityUpdate.d.ts.map +1 -1
- package/lib/chain/validation/lightClientFinalityUpdate.js +4 -3
- package/lib/chain/validation/lightClientFinalityUpdate.js.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.d.ts +6 -4
- package/lib/chain/validation/lightClientOptimisticUpdate.d.ts.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.js +11 -11
- package/lib/chain/validation/lightClientOptimisticUpdate.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +21 -15
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -1
- package/lib/metrics/metrics/lodestar.js +3 -3
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/gossipsub.js +1 -1
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/scoringParameters.js +4 -4
- package/lib/network/gossip/scoringParameters.js.map +1 -1
- package/lib/network/network.d.ts +1 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +9 -9
- package/lib/network/network.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js +2 -1
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +1 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/subnets/attnetsService.d.ts.map +1 -1
- package/lib/network/subnets/attnetsService.js +1 -1
- package/lib/network/subnets/attnetsService.js.map +1 -1
- package/lib/node/notifier.js +1 -1
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +0 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +7 -6
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +2 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +8 -3
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +2 -1
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/util/clock.d.ts +8 -3
- package/lib/util/clock.d.ts.map +1 -1
- package/lib/util/clock.js +8 -5
- package/lib/util/clock.js.map +1 -1
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +4 -2
- package/lib/util/dataColumns.js.map +1 -1
- package/package.json +14 -14
- package/src/api/impl/beacon/blocks/index.ts +11 -2
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +25 -37
- package/src/chain/blocks/blockInput/blockInput.ts +7 -4
- package/src/chain/blocks/importBlock.ts +8 -12
- package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -2
- package/src/chain/blocks/writeBlockInputToDb.ts +1 -9
- package/src/chain/chain.ts +3 -16
- package/src/chain/lightClient/index.ts +11 -3
- package/src/chain/opPools/attestationPool.ts +2 -3
- package/src/chain/opPools/syncCommitteeMessagePool.ts +5 -3
- package/src/chain/opPools/types.ts +1 -1
- package/src/chain/prepareNextSlot.ts +8 -8
- package/src/chain/produceBlock/produceBlockBody.ts +16 -14
- package/src/chain/regen/interface.ts +1 -0
- package/src/chain/seenCache/seenGossipBlockInput.ts +10 -2
- package/src/chain/stateCache/persistentCheckpointsCache.ts +10 -8
- package/src/chain/validation/dataColumnSidecar.ts +1 -1
- package/src/chain/validation/lightClientFinalityUpdate.ts +4 -3
- package/src/chain/validation/lightClientOptimisticUpdate.ts +12 -11
- package/src/chain/validatorMonitor.ts +28 -17
- package/src/metrics/metrics/lodestar.ts +3 -3
- package/src/network/gossip/gossipsub.ts +1 -1
- package/src/network/gossip/scoringParameters.ts +4 -4
- package/src/network/network.ts +9 -9
- package/src/network/peers/peerManager.ts +2 -1
- package/src/network/processor/gossipHandlers.ts +1 -1
- package/src/network/subnets/attnetsService.ts +3 -6
- package/src/node/notifier.ts +1 -1
- package/src/sync/unknownBlock.ts +7 -6
- package/src/sync/utils/downloadByRange.ts +12 -6
- package/src/sync/utils/downloadByRoot.ts +12 -4
- package/src/util/clock.ts +14 -6
- package/src/util/dataColumns.ts +11 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
3
|
-
import {ForkName, ForkPostFulu, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
|
|
3
|
+
import {ForkName, ForkPostFulu, ForkPreGloas, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
|
|
4
4
|
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
5
5
|
import {RootHex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
|
|
6
6
|
import {LodestarError, Logger} from "@lodestar/utils";
|
|
@@ -155,6 +155,12 @@ export class SeenBlockInput {
|
|
|
155
155
|
let blockInput = this.blockInputs.get(blockRootHex) as IBlockInput;
|
|
156
156
|
if (!blockInput) {
|
|
157
157
|
const {forkName, daOutOfRange} = this.buildCommonProps(block.message.slot);
|
|
158
|
+
|
|
159
|
+
// TODO GLOAS: Implement
|
|
160
|
+
if (isForkPostGloas(forkName)) {
|
|
161
|
+
throw Error("Not implemented");
|
|
162
|
+
}
|
|
163
|
+
// Pre-deneb
|
|
158
164
|
if (!isForkPostDeneb(forkName)) {
|
|
159
165
|
blockInput = BlockInputPreData.createFromBlock({
|
|
160
166
|
block,
|
|
@@ -165,9 +171,10 @@ export class SeenBlockInput {
|
|
|
165
171
|
seenTimestampSec,
|
|
166
172
|
peerIdStr,
|
|
167
173
|
});
|
|
174
|
+
// Fulu Only
|
|
168
175
|
} else if (isForkPostFulu(forkName)) {
|
|
169
176
|
blockInput = BlockInputColumns.createFromBlock({
|
|
170
|
-
block: block as SignedBeaconBlock<ForkPostFulu>,
|
|
177
|
+
block: block as SignedBeaconBlock<ForkPostFulu & ForkPreGloas>,
|
|
171
178
|
blockRootHex,
|
|
172
179
|
daOutOfRange,
|
|
173
180
|
forkName,
|
|
@@ -177,6 +184,7 @@ export class SeenBlockInput {
|
|
|
177
184
|
seenTimestampSec,
|
|
178
185
|
peerIdStr,
|
|
179
186
|
});
|
|
187
|
+
// Deneb and Electra
|
|
180
188
|
} else {
|
|
181
189
|
blockInput = BlockInputBlobs.createFromBlock({
|
|
182
190
|
block: block as SignedBeaconBlock<ForkBlobsDA>,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
|
-
import {INTERVALS_PER_SLOT} from "@lodestar/params";
|
|
3
2
|
import {
|
|
4
3
|
CachedBeaconStateAllForks,
|
|
5
4
|
computeStartSlotAtEpoch,
|
|
@@ -59,6 +58,9 @@ type LoadedStateBytesData = {persistedKey: DatastoreKey; stateBytes: Uint8Array}
|
|
|
59
58
|
*/
|
|
60
59
|
export const DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY = 3;
|
|
61
60
|
|
|
61
|
+
// TODO GLOAS: re-evaluate this timing
|
|
62
|
+
const PROCESS_CHECKPOINT_STATES_BPS = 6667;
|
|
63
|
+
|
|
62
64
|
/**
|
|
63
65
|
* An implementation of CheckpointStateCache that keep up to n epoch checkpoint states in memory and persist the rest to disk
|
|
64
66
|
* - If it's more than `maxEpochsInMemory` epochs old, it will persist n last epochs to disk based on the view of the block
|
|
@@ -464,14 +466,14 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
464
466
|
}
|
|
465
467
|
|
|
466
468
|
const blockSlot = state.slot;
|
|
467
|
-
const
|
|
469
|
+
const processCPStatesTimeMs = state.config.getSlotComponentDurationMs(PROCESS_CHECKPOINT_STATES_BPS);
|
|
468
470
|
// we always have clock in production, fallback value is only for test
|
|
469
|
-
const
|
|
470
|
-
const
|
|
471
|
-
if (
|
|
472
|
-
//
|
|
473
|
-
// normally it should only persist checkpoint states at
|
|
474
|
-
await sleep(
|
|
471
|
+
const msFromSlot = this.clock?.msFromSlot(blockSlot) ?? processCPStatesTimeMs;
|
|
472
|
+
const msToProcessCPStates = processCPStatesTimeMs - msFromSlot;
|
|
473
|
+
if (msToProcessCPStates > 0) {
|
|
474
|
+
// At ~67% of slot is the most free time of every slot, take that chance to persist checkpoint states
|
|
475
|
+
// normally it should only persist checkpoint states at ~67% of slot 0 of epoch
|
|
476
|
+
await sleep(msToProcessCPStates, this.signal);
|
|
475
477
|
}
|
|
476
478
|
// at syncing time, it's critical to persist checkpoint states as soon as possible to avoid OOM during unfinality time
|
|
477
479
|
// if node is synced this is not a hot time because block comes late, we'll likely miss attestation already, or the block is orphaned
|
|
@@ -99,7 +99,7 @@ export async function validateGossipDataColumnSidecar(
|
|
|
99
99
|
// this is something we should change this in the future to make the code airtight to the spec.
|
|
100
100
|
// 7) [REJECT] The sidecar's block's parent passes validation.
|
|
101
101
|
const blockState = await chain.regen
|
|
102
|
-
.getBlockSlotState(parentRoot, blockHeader.slot, {dontTransferCache: true}, RegenCaller.
|
|
102
|
+
.getBlockSlotState(parentRoot, blockHeader.slot, {dontTransferCache: true}, RegenCaller.validateGossipDataColumn)
|
|
103
103
|
.catch(() => {
|
|
104
104
|
throw new DataColumnSidecarGossipError(GossipAction.IGNORE, {
|
|
105
105
|
code: DataColumnSidecarErrorCode.PARENT_UNKNOWN,
|
|
@@ -25,9 +25,10 @@ export function validateLightClientFinalityUpdate(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// [IGNORE] The finality_update is received after the block at signature_slot was given enough time to propagate
|
|
28
|
-
// through the network -- i.e. validate that
|
|
29
|
-
// (
|
|
30
|
-
|
|
28
|
+
// through the network -- i.e. validate that `get_sync_message_due_ms(epoch)`
|
|
29
|
+
// milliseconds (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) has
|
|
30
|
+
// transpired since the start of `signature_slot`.
|
|
31
|
+
if (updateReceivedTooEarly(config, chain.clock, gossipedFinalityUpdate)) {
|
|
31
32
|
throw new LightClientError(GossipAction.IGNORE, {
|
|
32
33
|
code: LightClientErrorCode.FINALITY_UPDATE_RECEIVED_TOO_EARLY,
|
|
33
34
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
3
2
|
import {LightClientOptimisticUpdate} from "@lodestar/types";
|
|
4
3
|
import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js";
|
|
5
4
|
import {assertLightClientServer} from "../../node/utils/lightclient.js";
|
|
5
|
+
import {IClock} from "../../util/clock.js";
|
|
6
6
|
import {GossipAction} from "../errors/index.js";
|
|
7
7
|
import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js";
|
|
8
8
|
import {IBeaconChain} from "../interface.js";
|
|
@@ -26,9 +26,10 @@ export function validateLightClientOptimisticUpdate(
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// [IGNORE] The optimistic_update is received after the block at signature_slot was given enough time to propagate
|
|
29
|
-
// through the network -- i.e. validate that
|
|
30
|
-
// (
|
|
31
|
-
|
|
29
|
+
// through the network -- i.e. validate that `get_sync_message_due_ms(epoch)`
|
|
30
|
+
// milliseconds (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) has
|
|
31
|
+
// transpired since the start of `signature_slot`.
|
|
32
|
+
if (updateReceivedTooEarly(config, chain.clock, gossipedOptimisticUpdate)) {
|
|
32
33
|
throw new LightClientError(GossipAction.IGNORE, {
|
|
33
34
|
code: LightClientErrorCode.OPTIMISTIC_UPDATE_RECEIVED_TOO_EARLY,
|
|
34
35
|
});
|
|
@@ -48,20 +49,20 @@ export function validateLightClientOptimisticUpdate(
|
|
|
48
49
|
/**
|
|
49
50
|
* Returns true, if the spec condition below triggers an IGNORE.
|
|
50
51
|
*
|
|
51
|
-
* Sig +
|
|
52
|
+
* Sig + SYNC_MESSAGE_DUE_BPS time
|
|
52
53
|
* -----|-----
|
|
53
54
|
* xxx|------- (x is not okay)
|
|
54
55
|
*
|
|
55
56
|
* [IGNORE] The *update is received after the block at signature_slot was given enough time to propagate
|
|
56
|
-
* through the network -- i.e. validate that
|
|
57
|
-
* (
|
|
57
|
+
* through the network -- i.e. validate that `get_sync_message_due_ms(epoch)`
|
|
58
|
+
* milliseconds (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) has
|
|
59
|
+
* transpired since the start of `signature_slot`.
|
|
58
60
|
*/
|
|
59
61
|
export function updateReceivedTooEarly(
|
|
60
62
|
config: ChainForkConfig,
|
|
61
|
-
|
|
63
|
+
clock: IClock,
|
|
62
64
|
update: Pick<LightClientOptimisticUpdate, "signatureSlot">
|
|
63
65
|
): boolean {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
return Date.now() < earliestAllowedTimestampMs;
|
|
66
|
+
const fork = config.getForkName(update.signatureSlot);
|
|
67
|
+
return clock.msFromSlot(update.signatureSlot) < config.getSyncMessageDueMs(fork) - MAXIMUM_GOSSIP_CLOCK_DISPARITY;
|
|
67
68
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {ForkSeq,
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {ForkSeq, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
CachedBeaconStateAllForks,
|
|
5
5
|
CachedBeaconStateAltair,
|
|
6
6
|
ParticipationFlags,
|
|
7
7
|
computeEpochAtSlot,
|
|
8
8
|
computeStartSlotAtEpoch,
|
|
9
|
+
computeTimeAtSlot,
|
|
9
10
|
getBlockRootAtSlot,
|
|
10
11
|
getCurrentSlot,
|
|
11
12
|
parseAttesterFlags,
|
|
@@ -34,8 +35,9 @@ const MAX_CACHED_EPOCHS = 4;
|
|
|
34
35
|
|
|
35
36
|
const MAX_CACHED_DISTINCT_TARGETS = 4;
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
const
|
|
38
|
+
// TODO GLOAS: re-evaluate these timings
|
|
39
|
+
const LATE_ATTESTATION_SUBMISSION_BPS = 5000;
|
|
40
|
+
const LATE_BLOCK_SUBMISSION_BPS = 2500;
|
|
39
41
|
|
|
40
42
|
const RETAIN_REGISTERED_VALIDATORS_MS = 1 * 3600 * 1000; // 1 hour
|
|
41
43
|
|
|
@@ -450,8 +452,11 @@ export function createValidatorMonitor(
|
|
|
450
452
|
|
|
451
453
|
onPoolSubmitUnaggregatedAttestation(seenTimestampSec, indexedAttestation, subnet, sentPeers) {
|
|
452
454
|
const data = indexedAttestation.data;
|
|
453
|
-
|
|
454
|
-
|
|
455
|
+
const fork = config.getForkName(data.slot);
|
|
456
|
+
// Returns the duration between when the attestation `data` could be produced (ATTESTATION_DUE_BPS through the slot) and `seenTimestamp`.
|
|
457
|
+
const delaySec =
|
|
458
|
+
seenTimestampSec -
|
|
459
|
+
(computeTimeAtSlot(config, data.slot, genesisTime) + config.getAttestationDueMs(fork) / 1000);
|
|
455
460
|
for (const index of indexedAttestation.attestingIndices) {
|
|
456
461
|
const validator = validators.get(index);
|
|
457
462
|
if (validator) {
|
|
@@ -483,8 +488,11 @@ export function createValidatorMonitor(
|
|
|
483
488
|
const src = OpSource.gossip;
|
|
484
489
|
const data = indexedAttestation.data;
|
|
485
490
|
const epoch = computeEpochAtSlot(data.slot);
|
|
486
|
-
|
|
487
|
-
|
|
491
|
+
const fork = config.getForkName(data.slot);
|
|
492
|
+
// Returns the duration between when the attestation `data` could be produced (ATTESTATION_DUE_BPS through the slot) and `seenTimestamp`.
|
|
493
|
+
const delaySec =
|
|
494
|
+
seenTimestampSec -
|
|
495
|
+
(computeTimeAtSlot(config, data.slot, genesisTime) + config.getAttestationDueMs(fork) / 1000);
|
|
488
496
|
|
|
489
497
|
for (const index of indexedAttestation.attestingIndices) {
|
|
490
498
|
const validator = validators.get(index);
|
|
@@ -500,8 +508,10 @@ export function createValidatorMonitor(
|
|
|
500
508
|
|
|
501
509
|
onPoolSubmitAggregatedAttestation(seenTimestampSec, indexedAttestation, sentPeers) {
|
|
502
510
|
const data = indexedAttestation.data;
|
|
503
|
-
|
|
504
|
-
|
|
511
|
+
const fork = config.getForkName(data.slot);
|
|
512
|
+
// Returns the duration between when a `AggregateAndproof` with `data` could be produced (AGGREGATE_DUE_BPS through the slot) and `seenTimestamp`.
|
|
513
|
+
const delaySec =
|
|
514
|
+
seenTimestampSec - (computeTimeAtSlot(config, data.slot, genesisTime) + config.getAggregateDueMs(fork) / 1000);
|
|
505
515
|
|
|
506
516
|
for (const index of indexedAttestation.attestingIndices) {
|
|
507
517
|
const validator = validators.get(index);
|
|
@@ -527,8 +537,10 @@ export function createValidatorMonitor(
|
|
|
527
537
|
const src = OpSource.gossip;
|
|
528
538
|
const data = indexedAttestation.data;
|
|
529
539
|
const epoch = computeEpochAtSlot(data.slot);
|
|
530
|
-
|
|
531
|
-
|
|
540
|
+
const fork = config.getForkName(data.slot);
|
|
541
|
+
// Returns the duration between when a `AggregateAndproof` with `data` could be produced (AGGREGATE_DUE_BPS through the slot) and `seenTimestamp`.
|
|
542
|
+
const delaySec =
|
|
543
|
+
seenTimestampSec - (computeTimeAtSlot(config, data.slot, genesisTime) + config.getAggregateDueMs(fork) / 1000);
|
|
532
544
|
|
|
533
545
|
const aggregatorIndex = signedAggregateAndProof.message.aggregatorIndex;
|
|
534
546
|
const validatorAggregator = validators.get(aggregatorIndex);
|
|
@@ -822,7 +834,7 @@ export function createValidatorMonitor(
|
|
|
822
834
|
* - Was the attestation seen in a block?
|
|
823
835
|
*/
|
|
824
836
|
function renderAttestationSummary(
|
|
825
|
-
config:
|
|
837
|
+
config: ChainForkConfig,
|
|
826
838
|
rootCache: RootHexCache,
|
|
827
839
|
summary: AttestationSummary | undefined,
|
|
828
840
|
flags: ParticipationFlags
|
|
@@ -925,8 +937,7 @@ function renderAttestationSummary(
|
|
|
925
937
|
}
|
|
926
938
|
|
|
927
939
|
const submittedLate =
|
|
928
|
-
summary.poolSubmitDelayMinSec >
|
|
929
|
-
(INTERVALS_LATE_ATTESTATION_SUBMISSION * config.SECONDS_PER_SLOT) / INTERVALS_PER_SLOT;
|
|
940
|
+
summary.poolSubmitDelayMinSec > config.getSlotComponentDurationMs(LATE_ATTESTATION_SUBMISSION_BPS) / 1000;
|
|
930
941
|
|
|
931
942
|
const aggregateInclusion = summary.aggregateInclusionDelaysSec.length > 0;
|
|
932
943
|
|
|
@@ -1030,7 +1041,7 @@ function isMissedSlot(rootCache: RootHexCache, slot: Slot): boolean {
|
|
|
1030
1041
|
}
|
|
1031
1042
|
|
|
1032
1043
|
function renderBlockProposalSummary(
|
|
1033
|
-
config:
|
|
1044
|
+
config: ChainForkConfig,
|
|
1034
1045
|
rootCache: RootHexCache,
|
|
1035
1046
|
summary: EpochSummary | undefined,
|
|
1036
1047
|
proposalSlot: Slot
|
|
@@ -1053,7 +1064,7 @@ function renderBlockProposalSummary(
|
|
|
1053
1064
|
|
|
1054
1065
|
if (
|
|
1055
1066
|
proposal.poolSubmitDelaySec !== null &&
|
|
1056
|
-
proposal.poolSubmitDelaySec >
|
|
1067
|
+
proposal.poolSubmitDelaySec > config.getSlotComponentDurationMs(LATE_BLOCK_SUBMISSION_BPS) / 1000
|
|
1057
1068
|
) {
|
|
1058
1069
|
out += "_late";
|
|
1059
1070
|
}
|
|
@@ -862,9 +862,9 @@ export function createLodestarMetrics(
|
|
|
862
862
|
help: "Time elapsed between block slot time and the time block becomes head",
|
|
863
863
|
buckets: [0.5, 1, 2, 4, 6, 12],
|
|
864
864
|
}),
|
|
865
|
-
|
|
866
|
-
name: "
|
|
867
|
-
help: "Total times an imported block is set as head after the
|
|
865
|
+
setHeadAfterCutoff: register.gauge({
|
|
866
|
+
name: "lodestar_import_block_set_head_after_cutoff_total",
|
|
867
|
+
help: "Total times an imported block is set as head after ATTESTATION_DUE_BPS of the slot",
|
|
868
868
|
}),
|
|
869
869
|
bySource: register.gauge<{source: BlockInputSource}>({
|
|
870
870
|
name: "lodestar_import_block_by_source_total",
|
|
@@ -105,7 +105,7 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
105
105
|
mcacheLength: 6,
|
|
106
106
|
mcacheGossip: 3,
|
|
107
107
|
// this should be in ms
|
|
108
|
-
seenTTL: config.
|
|
108
|
+
seenTTL: config.SLOT_DURATION_MS * SLOTS_PER_EPOCH * 2,
|
|
109
109
|
scoreParams,
|
|
110
110
|
scoreThresholds: gossipScoreThresholds,
|
|
111
111
|
// For a single stream, await processing each RPC before processing the next
|
|
@@ -84,10 +84,10 @@ export function computeGossipPeerScoreParams({
|
|
|
84
84
|
config: BeaconConfig;
|
|
85
85
|
eth2Context: Eth2Context;
|
|
86
86
|
}): Partial<PeerScoreParams> {
|
|
87
|
-
const decayIntervalMs = config.
|
|
87
|
+
const decayIntervalMs = config.SLOT_DURATION_MS;
|
|
88
88
|
const decayToZero = 0.01;
|
|
89
|
-
const epochDurationMs = config.
|
|
90
|
-
const slotDurationMs = config.
|
|
89
|
+
const epochDurationMs = config.SLOT_DURATION_MS * SLOTS_PER_EPOCH;
|
|
90
|
+
const slotDurationMs = config.SLOT_DURATION_MS;
|
|
91
91
|
const scoreParameterDecayFn = (decayTimeMs: number): number => {
|
|
92
92
|
return scoreParameterDecayWithBase(decayTimeMs, decayIntervalMs, decayToZero);
|
|
93
93
|
};
|
|
@@ -265,7 +265,7 @@ function getTopicScoreParams(
|
|
|
265
265
|
|
|
266
266
|
if (meshMessageInfo) {
|
|
267
267
|
const {decaySlots, capFactor, activationWindow, currentSlot} = meshMessageInfo;
|
|
268
|
-
const decayTimeMs = config.
|
|
268
|
+
const decayTimeMs = config.SLOT_DURATION_MS * decaySlots;
|
|
269
269
|
params.meshMessageDeliveriesDecay = scoreParameterDecayFn(decayTimeMs);
|
|
270
270
|
params.meshMessageDeliveriesThreshold = threshold(params.meshMessageDeliveriesDecay, expectedMessageRate / 50);
|
|
271
271
|
params.meshMessageDeliveriesCap = Math.max(capFactor * params.meshMessageDeliveriesThreshold, 2);
|
package/src/network/network.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {BeaconConfig} from "@lodestar/config";
|
|
|
7
7
|
import {LoggerNode} from "@lodestar/logger/node";
|
|
8
8
|
import {ForkSeq} from "@lodestar/params";
|
|
9
9
|
import {ResponseIncoming} from "@lodestar/reqresp";
|
|
10
|
-
import {computeEpochAtSlot
|
|
10
|
+
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
11
11
|
import {
|
|
12
12
|
AttesterSlashing,
|
|
13
13
|
LightClientBootstrap,
|
|
@@ -689,9 +689,9 @@ export class Network implements INetwork {
|
|
|
689
689
|
// TODO: Review is OK to remove if (this.hasAttachedSyncCommitteeMember())
|
|
690
690
|
|
|
691
691
|
try {
|
|
692
|
-
// messages SHOULD be broadcast after
|
|
692
|
+
// messages SHOULD be broadcast after SYNC_MESSAGE_DUE_BPS of slot has transpired
|
|
693
693
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#sync-committee
|
|
694
|
-
await this.
|
|
694
|
+
await this.waitForSyncMessageCutoff(finalityUpdate.signatureSlot);
|
|
695
695
|
await this.publishLightClientFinalityUpdate(finalityUpdate);
|
|
696
696
|
} catch (e) {
|
|
697
697
|
// Non-mandatory route on most of network as of Oct 2022. May not have found any peers on topic yet
|
|
@@ -706,9 +706,9 @@ export class Network implements INetwork {
|
|
|
706
706
|
// TODO: Review is OK to remove if (this.hasAttachedSyncCommitteeMember())
|
|
707
707
|
|
|
708
708
|
try {
|
|
709
|
-
// messages SHOULD be broadcast after
|
|
709
|
+
// messages SHOULD be broadcast after SYNC_MESSAGE_DUE_BPS of slot has transpired
|
|
710
710
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#sync-committee
|
|
711
|
-
await this.
|
|
711
|
+
await this.waitForSyncMessageCutoff(optimisticUpdate.signatureSlot);
|
|
712
712
|
await this.publishLightClientOptimisticUpdate(optimisticUpdate);
|
|
713
713
|
} catch (e) {
|
|
714
714
|
// Non-mandatory route on most of network as of Oct 2022. May not have found any peers on topic yet
|
|
@@ -719,10 +719,10 @@ export class Network implements INetwork {
|
|
|
719
719
|
}
|
|
720
720
|
};
|
|
721
721
|
|
|
722
|
-
private
|
|
723
|
-
const
|
|
724
|
-
const
|
|
725
|
-
await sleep(
|
|
722
|
+
private waitForSyncMessageCutoff = async (slot: number): Promise<void> => {
|
|
723
|
+
const fork = this.config.getForkName(slot);
|
|
724
|
+
const msToCutoffTime = this.config.getSyncMessageDueMs(fork) - this.chain.clock.msFromSlot(slot);
|
|
725
|
+
await sleep(msToCutoffTime, this.controller.signal);
|
|
726
726
|
};
|
|
727
727
|
|
|
728
728
|
private onHead = async (): Promise<void> => {
|
|
@@ -3,6 +3,7 @@ import {BitArray} from "@chainsafe/ssz";
|
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
4
|
import {LoggerNode} from "@lodestar/logger/node";
|
|
5
5
|
import {ForkSeq, SLOTS_PER_EPOCH, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
|
|
6
|
+
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
6
7
|
import {Metadata, Status, altair, fulu, phase0} from "@lodestar/types";
|
|
7
8
|
import {prettyPrintIndices, toHex, withTimeout} from "@lodestar/utils";
|
|
8
9
|
import {GOODBYE_KNOWN_CODES, GoodByeReasonCode, Libp2pEvent} from "../../constants/index.js";
|
|
@@ -599,7 +600,7 @@ export class PeerManager {
|
|
|
599
600
|
subnet: query.subnet,
|
|
600
601
|
type,
|
|
601
602
|
maxPeersToDiscover: query.maxPeersToDiscover,
|
|
602
|
-
toUnixMs:
|
|
603
|
+
toUnixMs: computeTimeAtSlot(this.config, query.toSlot, this.clock.genesisTime) * 1000,
|
|
603
604
|
});
|
|
604
605
|
}
|
|
605
606
|
|
|
@@ -379,7 +379,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
379
379
|
|
|
380
380
|
// Handler - MUST NOT `await`, to allow validation result to be propagated
|
|
381
381
|
|
|
382
|
-
const delaySec = seenTimestampSec - (
|
|
382
|
+
const delaySec = seenTimestampSec - computeTimeAtSlot(config, slot, chain.genesisTime);
|
|
383
383
|
metrics?.gossipBlock.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
384
384
|
chain.validatorMonitor?.registerBeaconBlock(OpSource.gossip, delaySec, signedBlock.message);
|
|
385
385
|
if (!blockInput.hasBlockAndAllData()) {
|
|
@@ -163,12 +163,9 @@ export class AttnetsService implements IAttnetsService {
|
|
|
163
163
|
*/
|
|
164
164
|
private onSlot = (clockSlot: Slot): void => {
|
|
165
165
|
try {
|
|
166
|
-
setTimeout(
|
|
167
|
-
()
|
|
168
|
-
|
|
169
|
-
},
|
|
170
|
-
this.config.SECONDS_PER_SLOT * 0.5 * 1000
|
|
171
|
-
);
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
this.onHalfSlot(clockSlot);
|
|
168
|
+
}, this.config.SLOT_DURATION_MS * 0.5);
|
|
172
169
|
|
|
173
170
|
for (const [dutiedSlot, dutiedInfo] of this.aggregatorSlotSubnet.entries()) {
|
|
174
171
|
if (dutiedSlot === clockSlot + this.opts.slotsToSubscribeBeforeAggregatorDuty) {
|
package/src/node/notifier.ts
CHANGED
|
@@ -157,7 +157,7 @@ export async function runNodeNotifier(modules: NodeNotifierModules): Promise<voi
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
function timeToNextHalfSlot(config: BeaconConfig, chain: IBeaconChain, isFirstTime: boolean): number {
|
|
160
|
-
const msPerSlot = config.
|
|
160
|
+
const msPerSlot = config.SLOT_DURATION_MS;
|
|
161
161
|
const msPerHalfSlot = msPerSlot / 2;
|
|
162
162
|
const msFromGenesis = Date.now() - chain.genesisTime * 1000;
|
|
163
163
|
const msToNextSlot =
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {ForkSeq
|
|
2
|
+
import {ForkSeq} from "@lodestar/params";
|
|
3
3
|
import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
|
|
4
|
+
import {computeTimeAtSlot} from "@lodestar/state-transition";
|
|
4
5
|
import {RootHex} from "@lodestar/types";
|
|
5
6
|
import {Logger, prettyPrintIndices, pruneSetToMax, sleep} from "@lodestar/utils";
|
|
6
7
|
import {isBlockInputBlobs, isBlockInputColumns} from "../chain/blocks/blockInput/blockInput.js";
|
|
@@ -78,7 +79,6 @@ export class BlockInputSync {
|
|
|
78
79
|
*/
|
|
79
80
|
private readonly pendingBlocks = new Map<RootHex, BlockInputSyncCacheItem>();
|
|
80
81
|
private readonly knownBadBlocks = new Set<RootHex>();
|
|
81
|
-
private readonly proposerBoostSecWindow: number;
|
|
82
82
|
private readonly maxPendingBlocks;
|
|
83
83
|
private subscribedToNetworkEvents = false;
|
|
84
84
|
private peerBalancer: UnknownBlockPeerBalancer;
|
|
@@ -92,7 +92,6 @@ export class BlockInputSync {
|
|
|
92
92
|
private readonly opts?: SyncOptions
|
|
93
93
|
) {
|
|
94
94
|
this.maxPendingBlocks = opts?.maxPendingBlocks ?? MAX_PENDING_BLOCKS;
|
|
95
|
-
this.proposerBoostSecWindow = this.config.SECONDS_PER_SLOT / INTERVALS_PER_SLOT;
|
|
96
95
|
this.peerBalancer = new UnknownBlockPeerBalancer();
|
|
97
96
|
|
|
98
97
|
if (metrics) {
|
|
@@ -331,7 +330,7 @@ export class BlockInputSync {
|
|
|
331
330
|
this.pendingBlocks.set(pending.blockInput.blockRootHex, pending);
|
|
332
331
|
const blockSlot = pending.blockInput.slot;
|
|
333
332
|
const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
|
|
334
|
-
const delaySec = Date.now() / 1000 - (this.
|
|
333
|
+
const delaySec = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.chain.genesisTime);
|
|
335
334
|
this.metrics?.blockInputSync.elapsedTimeTillReceived.observe(delaySec);
|
|
336
335
|
|
|
337
336
|
const parentInForkChoice = this.chain.forkChoice.hasBlockHex(pending.blockInput.parentRootHex);
|
|
@@ -396,8 +395,10 @@ export class BlockInputSync {
|
|
|
396
395
|
// this prevents unbundling attack
|
|
397
396
|
// see https://lighthouse-blog.sigmaprime.io/mev-unbundling-rpc.html
|
|
398
397
|
const {slot: blockSlot, proposerIndex} = pendingBlock.blockInput.getBlock().message;
|
|
398
|
+
const fork = this.config.getForkName(blockSlot);
|
|
399
|
+
const proposerBoostWindowMs = this.config.getAttestationDueMs(fork);
|
|
399
400
|
if (
|
|
400
|
-
this.chain.clock.
|
|
401
|
+
this.chain.clock.msFromSlot(blockSlot) < proposerBoostWindowMs &&
|
|
401
402
|
this.chain.seenBlockProposers.isKnown(blockSlot, proposerIndex)
|
|
402
403
|
) {
|
|
403
404
|
// proposer is known by a gossip block already, wait a bit to make sure this block is not
|
|
@@ -407,7 +408,7 @@ export class BlockInputSync {
|
|
|
407
408
|
root: pendingBlock.blockInput.blockRootHex,
|
|
408
409
|
proposerIndex,
|
|
409
410
|
});
|
|
410
|
-
await sleep(
|
|
411
|
+
await sleep(proposerBoostWindowMs);
|
|
411
412
|
}
|
|
412
413
|
// At gossip time, it's critical to keep a good number of mesh peers.
|
|
413
414
|
// To do that, the Gossip Job Wait Time should be consistently <3s to avoid the behavior penalties in gossip
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {ForkPostDeneb, ForkPostFulu} from "@lodestar/params";
|
|
2
|
+
import {ForkPostDeneb, ForkPostFulu, ForkPreFulu, ForkPreGloas} from "@lodestar/params";
|
|
3
3
|
import {SignedBeaconBlock, Slot, deneb, fulu, phase0} from "@lodestar/types";
|
|
4
4
|
import {LodestarError, Logger, fromHex, prettyBytes, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
5
5
|
import {
|
|
@@ -458,14 +458,16 @@ export function validateBlockByRangeResponse(
|
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
/**
|
|
461
|
-
* Should not be called directly. Only exported for unit testing purposes
|
|
461
|
+
* Should not be called directly. Only exported for unit testing purposes.
|
|
462
|
+
* This is used only in Deneb and Electra
|
|
462
463
|
*/
|
|
463
464
|
export async function validateBlobsByRangeResponse(
|
|
464
465
|
dataRequestBlocks: ValidatedBlock[],
|
|
465
466
|
blobSidecars: deneb.BlobSidecars
|
|
466
467
|
): Promise<ValidatedBlobSidecars[]> {
|
|
467
468
|
const expectedBlobCount = dataRequestBlocks.reduce(
|
|
468
|
-
(acc, {block}) =>
|
|
469
|
+
(acc, {block}) =>
|
|
470
|
+
(block as SignedBeaconBlock<ForkPostDeneb & ForkPreFulu>).message.body.blobKzgCommitments.length + acc,
|
|
469
471
|
0
|
|
470
472
|
);
|
|
471
473
|
if (blobSidecars.length > expectedBlobCount) {
|
|
@@ -492,7 +494,8 @@ export async function validateBlobsByRangeResponse(
|
|
|
492
494
|
const validateSidecarsPromises: Promise<ValidatedBlobSidecars>[] = [];
|
|
493
495
|
for (let blockIndex = 0, blobSidecarIndex = 0; blockIndex < dataRequestBlocks.length; blockIndex++) {
|
|
494
496
|
const {block, blockRoot} = dataRequestBlocks[blockIndex];
|
|
495
|
-
const blockKzgCommitments = (block as SignedBeaconBlock<ForkPostDeneb>).message.body
|
|
497
|
+
const blockKzgCommitments = (block as SignedBeaconBlock<ForkPostDeneb & ForkPreFulu>).message.body
|
|
498
|
+
.blobKzgCommitments;
|
|
496
499
|
if (blockKzgCommitments.length === 0) {
|
|
497
500
|
continue;
|
|
498
501
|
}
|
|
@@ -532,8 +535,9 @@ export async function validateColumnsByRangeResponse(
|
|
|
532
535
|
columnSidecars: fulu.DataColumnSidecars
|
|
533
536
|
): Promise<WarnResult<ValidatedColumnSidecars[], DownloadByRangeError>> {
|
|
534
537
|
// Expected column count considering currently-validated batch blocks
|
|
538
|
+
// TODO GLOAS: Post-gloas's blobKzgCommitments is not in beacon block body. Need to source it from somewhere else.
|
|
535
539
|
const expectedColumnCount = dataRequestBlocks.reduce((acc, {block}) => {
|
|
536
|
-
return (block as SignedBeaconBlock<ForkPostDeneb>).message.body.blobKzgCommitments.length > 0
|
|
540
|
+
return (block as SignedBeaconBlock<ForkPostDeneb & ForkPreGloas>).message.body.blobKzgCommitments.length > 0
|
|
537
541
|
? request.columns.length + acc
|
|
538
542
|
: acc;
|
|
539
543
|
}, 0);
|
|
@@ -566,7 +570,9 @@ export async function validateColumnsByRangeResponse(
|
|
|
566
570
|
const {block, blockRoot} = dataRequestBlocks[blockIndex];
|
|
567
571
|
const slot = block.message.slot;
|
|
568
572
|
const blockRootHex = toRootHex(blockRoot);
|
|
569
|
-
|
|
573
|
+
// TODO GLOAS: Post-gloas's blobKzgCommitments is not in beacon block body. Need to source it from somewhere else.
|
|
574
|
+
const blockKzgCommitments = (block as SignedBeaconBlock<ForkPostFulu & ForkPreGloas>).message.body
|
|
575
|
+
.blobKzgCommitments;
|
|
570
576
|
const expectedColumns = blockKzgCommitments.length ? request.columns.length : 0;
|
|
571
577
|
|
|
572
578
|
if (expectedColumns === 0) {
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
ForkPostDeneb,
|
|
5
|
+
ForkPostFulu,
|
|
6
|
+
ForkPreFulu,
|
|
7
|
+
ForkPreGloas,
|
|
8
|
+
isForkPostDeneb,
|
|
9
|
+
isForkPostFulu,
|
|
10
|
+
} from "@lodestar/params";
|
|
11
|
+
import {BeaconBlockBody, BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
|
|
5
12
|
import {LodestarError, fromHex, prettyBytes, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
|
|
6
13
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
7
14
|
import {BlockInputSource, IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
@@ -269,7 +276,7 @@ export async function fetchByRoot({
|
|
|
269
276
|
missing: network.custodyConfig.sampledColumns,
|
|
270
277
|
});
|
|
271
278
|
} else if (isForkPostDeneb(forkName)) {
|
|
272
|
-
const commitments = (block as SignedBeaconBlock<ForkPostDeneb>).message.body.blobKzgCommitments;
|
|
279
|
+
const commitments = (block as SignedBeaconBlock<ForkPostDeneb & ForkPreFulu>).message.body.blobKzgCommitments;
|
|
273
280
|
const blobCount = commitments.length;
|
|
274
281
|
blobSidecars = await fetchAndValidateBlobs({
|
|
275
282
|
config,
|
|
@@ -369,7 +376,8 @@ export async function fetchAndValidateColumns({
|
|
|
369
376
|
}: FetchByRootAndValidateColumnsProps): Promise<WarnResult<fulu.DataColumnSidecars, DownloadByRootError>> {
|
|
370
377
|
const {peerId: peerIdStr} = peerMeta;
|
|
371
378
|
const slot = block.message.slot;
|
|
372
|
-
|
|
379
|
+
// TODO GLOAS: Get blob count from somewhere else since blobKzgCommitments is absent from block body
|
|
380
|
+
const blobCount = (block.message.body as BeaconBlockBody<ForkPostFulu & ForkPreGloas>).blobKzgCommitments.length;
|
|
373
381
|
if (blobCount === 0) {
|
|
374
382
|
return {result: [], warnings: null};
|
|
375
383
|
}
|
package/src/util/clock.ts
CHANGED
|
@@ -9,12 +9,12 @@ import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../constants/constants.js";
|
|
|
9
9
|
export enum ClockEvent {
|
|
10
10
|
/**
|
|
11
11
|
* This event signals the start of a new slot, and that subsequent calls to `clock.currentSlot` will equal `slot`.
|
|
12
|
-
* This event is guaranteed to be emitted every `
|
|
12
|
+
* This event is guaranteed to be emitted every `SLOT_DURATION_MS` milliseconds.
|
|
13
13
|
*/
|
|
14
14
|
slot = "clock:slot",
|
|
15
15
|
/**
|
|
16
16
|
* This event signals the start of a new epoch, and that subsequent calls to `clock.currentEpoch` will return `epoch`.
|
|
17
|
-
* This event is guaranteed to be emitted every `
|
|
17
|
+
* This event is guaranteed to be emitted every `SLOT_DURATION_MS * SLOTS_PER_EPOCH` milliseconds.
|
|
18
18
|
*/
|
|
19
19
|
epoch = "clock:epoch",
|
|
20
20
|
}
|
|
@@ -29,7 +29,7 @@ export type ClockEvents = {
|
|
|
29
29
|
*
|
|
30
30
|
* The time is dependent on:
|
|
31
31
|
* - `state.genesisTime` - the genesis time
|
|
32
|
-
* - `
|
|
32
|
+
* - `SLOT_DURATION_MS` - # of milliseconds per slot
|
|
33
33
|
* - `SLOTS_PER_EPOCH` - # of slots per epoch
|
|
34
34
|
*/
|
|
35
35
|
export type IClock = StrictEventEmitter<EventEmitter, ClockEvents> & {
|
|
@@ -58,6 +58,10 @@ export type IClock = StrictEventEmitter<EventEmitter, ClockEvents> & {
|
|
|
58
58
|
* Return second from a slot to either toSec or now.
|
|
59
59
|
*/
|
|
60
60
|
secFromSlot(slot: Slot, toSec?: number): number;
|
|
61
|
+
/**
|
|
62
|
+
* Return milliseconds from a slot to either toMs or now.
|
|
63
|
+
*/
|
|
64
|
+
msFromSlot(slot: Slot, toMs?: number): number;
|
|
61
65
|
};
|
|
62
66
|
|
|
63
67
|
/**
|
|
@@ -170,12 +174,16 @@ export class Clock extends EventEmitter implements IClock {
|
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
secFromSlot(slot: Slot, toSec = Date.now() / 1000): number {
|
|
173
|
-
return toSec - (this.
|
|
177
|
+
return toSec - computeTimeAtSlot(this.config, slot, this.genesisTime);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
msFromSlot(slot: Slot, toMs = Date.now()): number {
|
|
181
|
+
return toMs - computeTimeAtSlot(this.config, slot, this.genesisTime) * 1000;
|
|
174
182
|
}
|
|
175
183
|
|
|
176
184
|
private onNextSlot = (slot?: Slot): void => {
|
|
177
185
|
const clockSlot = slot ?? getCurrentSlot(this.config, this.genesisTime);
|
|
178
|
-
// process multiple clock slots in the case the main thread has been saturated for >
|
|
186
|
+
// process multiple clock slots in the case the main thread has been saturated for > SLOT_DURATION_MS
|
|
179
187
|
while (this._currentSlot < clockSlot && !this.signal.aborted) {
|
|
180
188
|
const previousSlot = this._currentSlot;
|
|
181
189
|
this._currentSlot++;
|
|
@@ -197,7 +205,7 @@ export class Clock extends EventEmitter implements IClock {
|
|
|
197
205
|
};
|
|
198
206
|
|
|
199
207
|
private msUntilNextSlot(): number {
|
|
200
|
-
const milliSecondsPerSlot = this.config.
|
|
208
|
+
const milliSecondsPerSlot = this.config.SLOT_DURATION_MS;
|
|
201
209
|
const diffInMilliSeconds = Date.now() - this.genesisTime * 1000;
|
|
202
210
|
return milliSecondsPerSlot - (diffInMilliSeconds % milliSecondsPerSlot);
|
|
203
211
|
}
|