@lodestar/beacon-node 1.35.0-dev.21ba2777a9 → 1.35.0-dev.248b252a94
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.js +1 -1
- 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 +20 -25
- 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 +1 -1
- 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.map +1 -1
- package/lib/chain/chain.js +3 -4
- package/lib/chain/chain.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/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/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/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/package.json +14 -14
- package/src/api/impl/beacon/blocks/index.ts +1 -1
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +21 -26
- package/src/chain/blocks/blockInput/blockInput.ts +2 -1
- 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 -14
- 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/stateCache/persistentCheckpointsCache.ts +10 -8
- 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/util/clock.ts +14 -6
|
@@ -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
|
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
|
}
|