@lodestar/beacon-node 1.36.0-dev.793f92c091 → 1.36.0-dev.a0d00ac6dc
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/config/constants.d.ts +4 -2
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +6 -3
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +2 -2
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +9 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +24 -0
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +7 -0
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +31 -5
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/beaconProposerCache.d.ts +3 -0
- package/lib/chain/beaconProposerCache.d.ts.map +1 -1
- package/lib/chain/beaconProposerCache.js +4 -6
- package/lib/chain/beaconProposerCache.js.map +1 -1
- package/lib/chain/chain.js +2 -2
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.d.ts +7 -0
- package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.js +1 -0
- package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
- package/lib/chain/errors/voluntaryExitError.d.ts +16 -2
- package/lib/chain/errors/voluntaryExitError.d.ts.map +1 -1
- package/lib/chain/errors/voluntaryExitError.js +22 -1
- package/lib/chain/errors/voluntaryExitError.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts +3 -0
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +24 -13
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.d.ts +3 -1
- package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js +4 -3
- package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +6 -7
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +1 -2
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +14 -3
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.d.ts.map +1 -1
- package/lib/chain/validation/lightClientOptimisticUpdate.js +1 -2
- package/lib/chain/validation/lightClientOptimisticUpdate.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +5 -4
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/constants/constants.d.ts +0 -5
- package/lib/constants/constants.d.ts.map +1 -1
- package/lib/constants/constants.js +0 -5
- package/lib/constants/constants.js.map +1 -1
- package/lib/constants/network.d.ts +0 -14
- package/lib/constants/network.d.ts.map +1 -1
- package/lib/constants/network.js +0 -15
- package/lib/constants/network.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +11 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +18 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/discv5/utils.d.ts.map +1 -1
- package/lib/network/discv5/utils.js +1 -2
- package/lib/network/discv5/utils.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +1 -7
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +1 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +14 -8
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +5 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +4 -4
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
- package/lib/network/subnets/attnetsService.d.ts +1 -1
- package/lib/network/subnets/attnetsService.js +6 -6
- package/lib/network/subnets/attnetsService.js.map +1 -1
- package/lib/network/subnets/util.d.ts +3 -2
- package/lib/network/subnets/util.d.ts.map +1 -1
- package/lib/network/subnets/util.js +6 -6
- package/lib/network/subnets/util.js.map +1 -1
- package/lib/sync/utils/remoteSyncType.js +2 -2
- package/lib/sync/utils/remoteSyncType.js.map +1 -1
- package/lib/util/clock.d.ts.map +1 -1
- package/lib/util/clock.js +3 -4
- package/lib/util/clock.js.map +1 -1
- package/package.json +26 -24
- package/src/api/impl/config/constants.ts +10 -4
- package/src/api/impl/validator/index.ts +5 -2
- package/src/chain/archiveStore/archiveStore.ts +27 -0
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +32 -5
- package/src/chain/beaconProposerCache.ts +4 -8
- package/src/chain/chain.ts +2 -2
- package/src/chain/errors/dataColumnSidecarError.ts +8 -0
- package/src/chain/errors/voluntaryExitError.ts +30 -2
- package/src/chain/lightClient/index.ts +26 -12
- package/src/chain/opPools/syncContributionAndProofPool.ts +3 -2
- package/src/chain/validation/attestation.ts +6 -7
- package/src/chain/validation/block.ts +1 -2
- package/src/chain/validation/dataColumnSidecar.ts +21 -4
- package/src/chain/validation/lightClientOptimisticUpdate.ts +3 -2
- package/src/chain/validation/voluntaryExit.ts +14 -4
- package/src/constants/constants.ts +0 -6
- package/src/constants/network.ts +0 -19
- package/src/metrics/metrics/lodestar.ts +21 -0
- package/src/network/discv5/utils.ts +1 -2
- package/src/network/gossip/gossipsub.ts +1 -10
- package/src/network/network.ts +1 -0
- package/src/network/processor/gossipHandlers.ts +16 -7
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +6 -6
- package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +5 -5
- package/src/network/subnets/attnetsService.ts +6 -6
- package/src/network/subnets/util.ts +12 -12
- package/src/sync/utils/remoteSyncType.ts +2 -2
- package/src/util/clock.ts +3 -4
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ATTESTATION_SUBNET_COUNT,
|
|
3
|
+
ATTESTATION_SUBNET_EXTRA_BITS,
|
|
4
|
+
ATTESTATION_SUBNET_PREFIX_BITS,
|
|
3
5
|
BASE_REWARDS_PER_EPOCH,
|
|
4
6
|
BLOB_TX_TYPE,
|
|
5
7
|
BLS_WITHDRAWAL_PREFIX,
|
|
@@ -25,15 +27,15 @@ import {
|
|
|
25
27
|
DOMAIN_SYNC_COMMITTEE,
|
|
26
28
|
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF,
|
|
27
29
|
DOMAIN_VOLUNTARY_EXIT,
|
|
28
|
-
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION,
|
|
29
30
|
ETH1_ADDRESS_WITHDRAWAL_PREFIX,
|
|
30
31
|
FAR_FUTURE_EPOCH,
|
|
31
32
|
FULL_EXIT_REQUEST_AMOUNT,
|
|
32
33
|
GENESIS_EPOCH,
|
|
33
34
|
GENESIS_SLOT,
|
|
34
35
|
JUSTIFICATION_BITS_LENGTH,
|
|
36
|
+
MAX_CONCURRENT_REQUESTS,
|
|
37
|
+
NODE_ID_BITS,
|
|
35
38
|
PROPOSER_WEIGHT,
|
|
36
|
-
RANDOM_SUBNETS_PER_VALIDATOR,
|
|
37
39
|
SYNC_COMMITTEE_SUBNET_COUNT,
|
|
38
40
|
SYNC_REWARD_WEIGHT,
|
|
39
41
|
TARGET_AGGREGATORS_PER_COMMITTEE,
|
|
@@ -84,9 +86,13 @@ export const specConstants = {
|
|
|
84
86
|
|
|
85
87
|
// phase0/validator.md
|
|
86
88
|
TARGET_AGGREGATORS_PER_COMMITTEE,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
|
|
90
|
+
// phase0/p2p-interface.md
|
|
91
|
+
NODE_ID_BITS,
|
|
92
|
+
MAX_CONCURRENT_REQUESTS,
|
|
89
93
|
ATTESTATION_SUBNET_COUNT,
|
|
94
|
+
ATTESTATION_SUBNET_EXTRA_BITS,
|
|
95
|
+
ATTESTATION_SUBNET_PREFIX_BITS,
|
|
90
96
|
|
|
91
97
|
// altair/beacon-chain.md
|
|
92
98
|
// ## Participation flag indices
|
|
@@ -179,10 +179,13 @@ export function getValidatorApi(
|
|
|
179
179
|
/**
|
|
180
180
|
* Validator clock may be advanced from beacon's clock. If the validator requests a resource in a
|
|
181
181
|
* future slot, wait some time instead of rejecting the request because it's in the future.
|
|
182
|
-
* This value is the same to
|
|
182
|
+
* This value is the same to MAXIMUM_GOSSIP_CLOCK_DISPARITY.
|
|
183
183
|
* For very fast networks, reduce clock disparity to half a slot.
|
|
184
184
|
*/
|
|
185
|
-
const MAX_API_CLOCK_DISPARITY_SEC = Math.min(
|
|
185
|
+
const MAX_API_CLOCK_DISPARITY_SEC = Math.min(
|
|
186
|
+
config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000,
|
|
187
|
+
config.SLOT_DURATION_MS / 2000
|
|
188
|
+
);
|
|
186
189
|
const MAX_API_CLOCK_DISPARITY_MS = MAX_API_CLOCK_DISPARITY_SEC * 1000;
|
|
187
190
|
|
|
188
191
|
/** Compute and cache the genesis block root */
|
|
@@ -25,6 +25,16 @@ type ArchiveStoreModules = {
|
|
|
25
25
|
|
|
26
26
|
type ArchiveStoreInitOpts = ArchiveStoreOpts & {dbName: string; anchorState: {finalizedCheckpoint: Checkpoint}};
|
|
27
27
|
|
|
28
|
+
export enum ArchiveStoreTask {
|
|
29
|
+
ArchiveBlocks = "archive_blocks",
|
|
30
|
+
PruneHistory = "prune_history",
|
|
31
|
+
OnFinalizedCheckpoint = "on_finalized_checkpoint",
|
|
32
|
+
MaybeArchiveState = "maybe_archive_state",
|
|
33
|
+
RegenPruneOnFinalized = "regen_prune_on_finalized",
|
|
34
|
+
ForkchoicePrune = "forkchoice_prune",
|
|
35
|
+
UpdateBackfillRange = "update_backfill_range",
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
/**
|
|
29
39
|
* Used for running tasks that depends on some events or are executed
|
|
30
40
|
* periodically.
|
|
@@ -176,6 +186,8 @@ export class ArchiveStore {
|
|
|
176
186
|
try {
|
|
177
187
|
const finalizedEpoch = finalized.epoch;
|
|
178
188
|
this.logger.verbose("Start processing finalized checkpoint", {epoch: finalizedEpoch, rootHex: finalized.rootHex});
|
|
189
|
+
|
|
190
|
+
let timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
179
191
|
await archiveBlocks(
|
|
180
192
|
this.chain.config,
|
|
181
193
|
this.db,
|
|
@@ -188,7 +200,10 @@ export class ArchiveStore {
|
|
|
188
200
|
this.chain.opts.persistOrphanedBlocks,
|
|
189
201
|
this.chain.opts.persistOrphanedBlocksDir
|
|
190
202
|
);
|
|
203
|
+
timer?.({source: ArchiveStoreTask.ArchiveBlocks});
|
|
204
|
+
|
|
191
205
|
if (this.opts.pruneHistory) {
|
|
206
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
192
207
|
await pruneHistory(
|
|
193
208
|
this.chain.config,
|
|
194
209
|
this.db,
|
|
@@ -197,18 +212,30 @@ export class ArchiveStore {
|
|
|
197
212
|
finalizedEpoch,
|
|
198
213
|
this.chain.clock.currentEpoch
|
|
199
214
|
);
|
|
215
|
+
timer?.({source: ArchiveStoreTask.PruneHistory});
|
|
200
216
|
}
|
|
201
217
|
|
|
218
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
202
219
|
await this.statesArchiverStrategy.onFinalizedCheckpoint(finalized, this.metrics);
|
|
220
|
+
timer?.({source: ArchiveStoreTask.OnFinalizedCheckpoint});
|
|
203
221
|
|
|
204
222
|
// should be after ArchiveBlocksTask to handle restart cleanly
|
|
223
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
205
224
|
await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics);
|
|
225
|
+
timer?.({source: ArchiveStoreTask.MaybeArchiveState});
|
|
206
226
|
|
|
227
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
207
228
|
this.chain.regen.pruneOnFinalized(finalizedEpoch);
|
|
229
|
+
timer?.({source: ArchiveStoreTask.RegenPruneOnFinalized});
|
|
208
230
|
|
|
209
231
|
// tasks rely on extended fork choice
|
|
232
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
210
233
|
const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex);
|
|
234
|
+
timer?.({source: ArchiveStoreTask.ForkchoicePrune});
|
|
235
|
+
|
|
236
|
+
timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
|
|
211
237
|
await updateBackfillRange({chain: this.chain, db: this.db, logger: this.logger}, finalized);
|
|
238
|
+
timer?.({source: ArchiveStoreTask.UpdateBackfillRange});
|
|
212
239
|
|
|
213
240
|
this.logger.verbose("Finish processing finalized checkpoint", {
|
|
214
241
|
epoch: finalizedEpoch,
|
|
@@ -17,6 +17,15 @@ import {StateArchiveStrategy, StatesArchiveOpts} from "../interface.js";
|
|
|
17
17
|
*/
|
|
18
18
|
export const PERSIST_TEMP_STATE_EVERY_EPOCHS = 32;
|
|
19
19
|
|
|
20
|
+
export enum FrequencyStateArchiveStep {
|
|
21
|
+
LoadLastStoredSlot = "load_last_stored_slot",
|
|
22
|
+
GetFinalizedState = "get_finalized_state",
|
|
23
|
+
// SerializeState is tracked via stateSerializeDuration metric
|
|
24
|
+
PersistState = "persist_state",
|
|
25
|
+
LoadStoredSlotsToDelete = "load_stored_slots_to_delete",
|
|
26
|
+
DeleteOldStates = "delete_old_states",
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
/**
|
|
21
30
|
* Archives finalized states from active bucket to archive bucket.
|
|
22
31
|
*
|
|
@@ -47,11 +56,16 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
47
56
|
* ```
|
|
48
57
|
*/
|
|
49
58
|
async maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise<void> {
|
|
59
|
+
let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
50
60
|
const lastStoredSlot = await this.db.stateArchive.lastKey();
|
|
61
|
+
timer?.({step: FrequencyStateArchiveStep.LoadLastStoredSlot});
|
|
62
|
+
|
|
51
63
|
const lastStoredEpoch = computeEpochAtSlot(lastStoredSlot ?? 0);
|
|
52
64
|
const {archiveStateEpochFrequency} = this.opts;
|
|
53
65
|
|
|
66
|
+
const logCtx = {finalizedEpoch: finalized.epoch, lastStoredEpoch, archiveStateEpochFrequency};
|
|
54
67
|
if (finalized.epoch - lastStoredEpoch >= Math.min(PERSIST_TEMP_STATE_EVERY_EPOCHS, archiveStateEpochFrequency)) {
|
|
68
|
+
this.logger.verbose("Start archiving state", logCtx);
|
|
55
69
|
await this.archiveState(finalized, metrics);
|
|
56
70
|
|
|
57
71
|
// Only check the current and previous intervals
|
|
@@ -60,23 +74,29 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
60
74
|
(Math.floor(finalized.epoch / archiveStateEpochFrequency) - 1) * archiveStateEpochFrequency
|
|
61
75
|
);
|
|
62
76
|
|
|
77
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
63
78
|
const storedStateSlots = await this.db.stateArchive.keys({
|
|
64
79
|
lt: computeStartSlotAtEpoch(finalized.epoch),
|
|
65
80
|
gte: computeStartSlotAtEpoch(minEpoch),
|
|
66
81
|
});
|
|
82
|
+
timer?.({step: FrequencyStateArchiveStep.LoadStoredSlotsToDelete});
|
|
67
83
|
|
|
68
84
|
const statesSlotsToDelete = computeStateSlotsToDelete(storedStateSlots, archiveStateEpochFrequency);
|
|
85
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
69
86
|
if (statesSlotsToDelete.length > 0) {
|
|
70
87
|
await this.db.stateArchive.batchDelete(statesSlotsToDelete);
|
|
71
88
|
}
|
|
89
|
+
timer?.({step: FrequencyStateArchiveStep.DeleteOldStates});
|
|
72
90
|
|
|
73
91
|
// More logs to investigate the rss spike issue https://github.com/ChainSafe/lodestar/issues/5591
|
|
74
92
|
this.logger.verbose("Archived state completed", {
|
|
75
|
-
|
|
93
|
+
...logCtx,
|
|
76
94
|
minEpoch,
|
|
77
95
|
storedStateSlots: storedStateSlots.join(","),
|
|
78
96
|
statesSlotsToDelete: statesSlotsToDelete.join(","),
|
|
79
97
|
});
|
|
98
|
+
} else {
|
|
99
|
+
this.logger.verbose("Skip archiving state", logCtx);
|
|
80
100
|
}
|
|
81
101
|
}
|
|
82
102
|
|
|
@@ -86,24 +106,31 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
|
|
|
86
106
|
*/
|
|
87
107
|
async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise<void> {
|
|
88
108
|
// starting from Mar 2024, the finalized state could be from disk or in memory
|
|
109
|
+
let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
89
110
|
const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized);
|
|
111
|
+
timer?.({step: FrequencyStateArchiveStep.GetFinalizedState});
|
|
112
|
+
|
|
90
113
|
const {rootHex} = finalized;
|
|
91
114
|
if (!finalizedStateOrBytes) {
|
|
92
115
|
throw Error(`No state in cache for finalized checkpoint state epoch #${finalized.epoch} root ${rootHex}`);
|
|
93
116
|
}
|
|
94
117
|
if (finalizedStateOrBytes instanceof Uint8Array) {
|
|
95
118
|
const slot = getStateSlotFromBytes(finalizedStateOrBytes);
|
|
119
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
96
120
|
await this.db.stateArchive.putBinary(slot, finalizedStateOrBytes);
|
|
121
|
+
timer?.({step: FrequencyStateArchiveStep.PersistState});
|
|
97
122
|
this.logger.verbose("Archived finalized state bytes", {epoch: finalized.epoch, slot, root: rootHex});
|
|
98
123
|
} else {
|
|
99
124
|
// serialize state using BufferPool if provided
|
|
100
|
-
const
|
|
125
|
+
const sszTimer = metrics?.stateSerializeDuration.startTimer({source: AllocSource.ARCHIVE_STATE});
|
|
101
126
|
await serializeState(
|
|
102
127
|
finalizedStateOrBytes,
|
|
103
128
|
AllocSource.ARCHIVE_STATE,
|
|
104
|
-
(stateBytes) => {
|
|
105
|
-
|
|
106
|
-
|
|
129
|
+
async (stateBytes) => {
|
|
130
|
+
sszTimer?.();
|
|
131
|
+
timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
|
|
132
|
+
await this.db.stateArchive.putBinary(finalizedStateOrBytes.slot, stateBytes);
|
|
133
|
+
timer?.({step: FrequencyStateArchiveStep.PersistState});
|
|
107
134
|
},
|
|
108
135
|
this.bufferPool
|
|
109
136
|
);
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {Epoch} from "@lodestar/types";
|
|
3
|
-
import {MapDef} from "@lodestar/utils";
|
|
4
3
|
|
|
5
4
|
const PROPOSER_PRESERVE_EPOCHS = 2;
|
|
6
5
|
|
|
7
6
|
export type ProposerPreparationData = routes.validator.ProposerPreparationData;
|
|
8
7
|
|
|
9
8
|
export class BeaconProposerCache {
|
|
10
|
-
private readonly feeRecipientByValidatorIndex:
|
|
11
|
-
constructor(opts: {suggestedFeeRecipient: string}) {
|
|
12
|
-
this.feeRecipientByValidatorIndex = new
|
|
13
|
-
epoch: 0,
|
|
14
|
-
feeRecipient: opts.suggestedFeeRecipient,
|
|
15
|
-
}));
|
|
9
|
+
private readonly feeRecipientByValidatorIndex: Map<number, {epoch: Epoch; feeRecipient: string}>;
|
|
10
|
+
constructor(readonly opts: {suggestedFeeRecipient: string}) {
|
|
11
|
+
this.feeRecipientByValidatorIndex = new Map();
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
add(epoch: Epoch, {validatorIndex, feeRecipient}: ProposerPreparationData): void {
|
|
@@ -30,7 +26,7 @@ export class BeaconProposerCache {
|
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
getOrDefault(proposerIndex: number): string {
|
|
33
|
-
return this.feeRecipientByValidatorIndex.
|
|
29
|
+
return this.feeRecipientByValidatorIndex.get(proposerIndex)?.feeRecipient ?? this.opts.suggestedFeeRecipient;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
get(proposerIndex: number): string | undefined {
|
package/src/chain/chain.ts
CHANGED
|
@@ -257,7 +257,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
257
257
|
this.attestationPool = new AttestationPool(config, clock, this.opts?.preaggregateSlotDistance, metrics);
|
|
258
258
|
this.aggregatedAttestationPool = new AggregatedAttestationPool(this.config, metrics);
|
|
259
259
|
this.syncCommitteeMessagePool = new SyncCommitteeMessagePool(config, clock, this.opts?.preaggregateSlotDistance);
|
|
260
|
-
this.syncContributionAndProofPool = new SyncContributionAndProofPool(clock, metrics, logger);
|
|
260
|
+
this.syncContributionAndProofPool = new SyncContributionAndProofPool(config, clock, metrics, logger);
|
|
261
261
|
|
|
262
262
|
this.seenAggregatedAttestations = new SeenAggregatedAttestations(metrics);
|
|
263
263
|
this.seenContributionAndProof = new SeenContributionAndProof(metrics);
|
|
@@ -372,7 +372,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
372
372
|
});
|
|
373
373
|
|
|
374
374
|
if (!opts.disableLightClientServer) {
|
|
375
|
-
this.lightClientServer = new LightClientServer(opts, {config, db, metrics, emitter, logger});
|
|
375
|
+
this.lightClientServer = new LightClientServer(opts, {config, clock, db, metrics, emitter, logger});
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
this.reprocessController = new ReprocessController(this.metrics);
|
|
@@ -8,6 +8,7 @@ export enum DataColumnSidecarErrorCode {
|
|
|
8
8
|
MISMATCHED_LENGTHS = "DATA_COLUMN_SIDECAR_ERROR_MISMATCHED_LENGTHS",
|
|
9
9
|
INVALID_SUBNET = "DATA_COLUMN_SIDECAR_ERROR_INVALID_SUBNET",
|
|
10
10
|
INVALID_KZG_PROOF = "DATA_COLUMN_SIDECAR_ERROR_INVALID_KZG_PROOF",
|
|
11
|
+
TOO_MANY_KZG_COMMITMENTS = "DATA_COLUMN_SIDECAR_ERROR_TOO_MANY_KZG_COMMITMENTS",
|
|
11
12
|
|
|
12
13
|
// Validation errors when validating against an existing block
|
|
13
14
|
|
|
@@ -43,6 +44,13 @@ export type DataColumnSidecarErrorType =
|
|
|
43
44
|
proofsLength: number;
|
|
44
45
|
}
|
|
45
46
|
| {code: DataColumnSidecarErrorCode.INVALID_SUBNET; columnIdx: number; gossipSubnet: SubnetID}
|
|
47
|
+
| {
|
|
48
|
+
code: DataColumnSidecarErrorCode.TOO_MANY_KZG_COMMITMENTS;
|
|
49
|
+
slot: number;
|
|
50
|
+
columnIdx: number;
|
|
51
|
+
count: number;
|
|
52
|
+
limit: number;
|
|
53
|
+
}
|
|
46
54
|
| {code: DataColumnSidecarErrorCode.ALREADY_KNOWN; columnIdx: number; slot: Slot}
|
|
47
55
|
| {code: DataColumnSidecarErrorCode.FUTURE_SLOT; blockSlot: Slot; currentSlot: Slot}
|
|
48
56
|
| {code: DataColumnSidecarErrorCode.WOULD_REVERT_FINALIZED_SLOT; blockSlot: Slot; finalizedSlot: Slot}
|
|
@@ -1,13 +1,41 @@
|
|
|
1
|
+
import {VoluntaryExitValidity} from "@lodestar/state-transition";
|
|
1
2
|
import {GossipActionError} from "./gossipValidation.js";
|
|
2
3
|
|
|
3
4
|
export enum VoluntaryExitErrorCode {
|
|
4
5
|
ALREADY_EXISTS = "VOLUNTARY_EXIT_ERROR_ALREADY_EXISTS",
|
|
5
|
-
|
|
6
|
+
INACTIVE = "VOLUNTARY_EXIT_ERROR_INACTIVE",
|
|
7
|
+
ALREADY_EXITED = "VOLUNTARY_EXIT_ERROR_ALREADY_EXITED",
|
|
8
|
+
EARLY_EPOCH = "VOLUNTARY_EXIT_ERROR_EARLY_EPOCH",
|
|
9
|
+
SHORT_TIME_ACTIVE = "VOLUNTARY_EXIT_ERROR_SHORT_TIME_ACTIVE",
|
|
10
|
+
PENDING_WITHDRAWALS = "VOLUNTARY_EXIT_ERROR_PENDING_WITHDRAWALS",
|
|
6
11
|
INVALID_SIGNATURE = "VOLUNTARY_EXIT_ERROR_INVALID_SIGNATURE",
|
|
7
12
|
}
|
|
8
13
|
export type VoluntaryExitErrorType =
|
|
9
14
|
| {code: VoluntaryExitErrorCode.ALREADY_EXISTS}
|
|
10
|
-
| {code: VoluntaryExitErrorCode.
|
|
15
|
+
| {code: VoluntaryExitErrorCode.INACTIVE}
|
|
16
|
+
| {code: VoluntaryExitErrorCode.ALREADY_EXITED}
|
|
17
|
+
| {code: VoluntaryExitErrorCode.EARLY_EPOCH}
|
|
18
|
+
| {code: VoluntaryExitErrorCode.SHORT_TIME_ACTIVE}
|
|
19
|
+
| {code: VoluntaryExitErrorCode.PENDING_WITHDRAWALS}
|
|
11
20
|
| {code: VoluntaryExitErrorCode.INVALID_SIGNATURE};
|
|
12
21
|
|
|
13
22
|
export class VoluntaryExitError extends GossipActionError<VoluntaryExitErrorType> {}
|
|
23
|
+
|
|
24
|
+
export function voluntaryExitValidityToErrorCode(
|
|
25
|
+
validity: Exclude<VoluntaryExitValidity, VoluntaryExitValidity.valid>
|
|
26
|
+
): VoluntaryExitErrorCode {
|
|
27
|
+
switch (validity) {
|
|
28
|
+
case VoluntaryExitValidity.inactive:
|
|
29
|
+
return VoluntaryExitErrorCode.INACTIVE;
|
|
30
|
+
case VoluntaryExitValidity.alreadyExited:
|
|
31
|
+
return VoluntaryExitErrorCode.ALREADY_EXITED;
|
|
32
|
+
case VoluntaryExitValidity.earlyEpoch:
|
|
33
|
+
return VoluntaryExitErrorCode.EARLY_EPOCH;
|
|
34
|
+
case VoluntaryExitValidity.shortTimeActive:
|
|
35
|
+
return VoluntaryExitErrorCode.SHORT_TIME_ACTIVE;
|
|
36
|
+
case VoluntaryExitValidity.pendingWithdrawals:
|
|
37
|
+
return VoluntaryExitErrorCode.PENDING_WITHDRAWALS;
|
|
38
|
+
case VoluntaryExitValidity.invalidSignature:
|
|
39
|
+
return VoluntaryExitErrorCode.INVALID_SIGNATURE;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
ForkPreGloas,
|
|
15
15
|
ForkSeq,
|
|
16
16
|
MIN_SYNC_COMMITTEE_PARTICIPANTS,
|
|
17
|
+
SLOTS_PER_EPOCH,
|
|
17
18
|
SYNC_COMMITTEE_SIZE,
|
|
18
19
|
forkPostAltair,
|
|
19
20
|
highestFork,
|
|
@@ -51,6 +52,7 @@ import {IBeaconDb} from "../../db/index.js";
|
|
|
51
52
|
import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../db/repositories/lightclientSyncCommitteeWitness.js";
|
|
52
53
|
import {Metrics} from "../../metrics/index.js";
|
|
53
54
|
import {byteArrayEquals} from "../../util/bytes.js";
|
|
55
|
+
import {IClock} from "../../util/clock.js";
|
|
54
56
|
import {ChainEventEmitter} from "../emitter.js";
|
|
55
57
|
import {LightClientServerError, LightClientServerErrorCode} from "../errors/lightClientError.js";
|
|
56
58
|
import {
|
|
@@ -86,6 +88,7 @@ export type SyncAttestedData = {
|
|
|
86
88
|
|
|
87
89
|
type LightClientServerModules = {
|
|
88
90
|
config: ChainForkConfig;
|
|
91
|
+
clock: IClock;
|
|
89
92
|
db: IBeaconDb;
|
|
90
93
|
metrics: Metrics | null;
|
|
91
94
|
emitter: ChainEventEmitter;
|
|
@@ -201,6 +204,7 @@ export class LightClientServer {
|
|
|
201
204
|
private readonly metrics: Metrics | null;
|
|
202
205
|
private readonly emitter: ChainEventEmitter;
|
|
203
206
|
private readonly logger: Logger;
|
|
207
|
+
private readonly clock: IClock;
|
|
204
208
|
private readonly knownSyncCommittee = new MapDef<SyncPeriod, Set<DependentRootHex>>(() => new Set());
|
|
205
209
|
private storedCurrentSyncCommittee = false;
|
|
206
210
|
|
|
@@ -221,8 +225,9 @@ export class LightClientServer {
|
|
|
221
225
|
private readonly opts: LightClientServerOpts,
|
|
222
226
|
modules: LightClientServerModules
|
|
223
227
|
) {
|
|
224
|
-
const {config, db, metrics, emitter, logger} = modules;
|
|
228
|
+
const {config, clock, db, metrics, emitter, logger} = modules;
|
|
225
229
|
this.config = config;
|
|
230
|
+
this.clock = clock;
|
|
226
231
|
this.db = db;
|
|
227
232
|
this.metrics = metrics;
|
|
228
233
|
this.emitter = emitter;
|
|
@@ -533,12 +538,19 @@ export class LightClientServer {
|
|
|
533
538
|
// Fork of LightClientOptimisticUpdate and LightClientFinalityUpdate is based off on attested header's fork
|
|
534
539
|
const attestedFork = this.config.getForkName(attestedHeader.beacon.slot);
|
|
535
540
|
|
|
536
|
-
//
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
541
|
+
// Check if node is syncing / too far behind to avoid emitting stale light client updates
|
|
542
|
+
const isStaleLightClientUpdate = this.clock.currentSlot - signatureSlot > SLOTS_PER_EPOCH;
|
|
543
|
+
|
|
544
|
+
if (!isStaleLightClientUpdate) {
|
|
545
|
+
// Emit update
|
|
546
|
+
// Note: Always emit optimistic update even if we have emitted one with higher or equal attested_header.slot
|
|
547
|
+
this.emitter.emit(routes.events.EventType.lightClientOptimisticUpdate, {
|
|
548
|
+
version: attestedFork,
|
|
549
|
+
data: headerUpdate,
|
|
550
|
+
});
|
|
551
|
+
} else {
|
|
552
|
+
this.metrics?.lightclientServer.staleLightClientUpdates.inc();
|
|
553
|
+
}
|
|
542
554
|
|
|
543
555
|
// Persist latest best update for getLatestHeadUpdate()
|
|
544
556
|
// TODO: Once SyncAggregate are constructed from P2P too, count bits to decide "best"
|
|
@@ -569,11 +581,13 @@ export class LightClientServer {
|
|
|
569
581
|
};
|
|
570
582
|
this.metrics?.lightclientServer.onSyncAggregate.inc({event: "update_latest_finalized_update"});
|
|
571
583
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
584
|
+
if (!isStaleLightClientUpdate) {
|
|
585
|
+
// Note: Ignores gossip rule to always emit finality_update with higher finalized_header.slot, for simplicity
|
|
586
|
+
this.emitter.emit(routes.events.EventType.lightClientFinalityUpdate, {
|
|
587
|
+
version: attestedFork,
|
|
588
|
+
data: this.finalized,
|
|
589
|
+
});
|
|
590
|
+
}
|
|
577
591
|
}
|
|
578
592
|
}
|
|
579
593
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {Signature, aggregateSignatures} from "@chainsafe/blst";
|
|
2
2
|
import {BitArray} from "@chainsafe/ssz";
|
|
3
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
3
4
|
import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
|
|
4
5
|
import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
|
|
5
6
|
import {Root, Slot, SubnetID, altair, ssz} from "@lodestar/types";
|
|
6
7
|
import {Logger, MapDef, toRootHex} from "@lodestar/utils";
|
|
7
|
-
import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/constants.js";
|
|
8
8
|
import {Metrics} from "../../metrics/metrics.js";
|
|
9
9
|
import {IClock} from "../../util/clock.js";
|
|
10
10
|
import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
|
|
@@ -51,6 +51,7 @@ export class SyncContributionAndProofPool {
|
|
|
51
51
|
private lowestPermissibleSlot = 0;
|
|
52
52
|
|
|
53
53
|
constructor(
|
|
54
|
+
private readonly config: ChainForkConfig,
|
|
54
55
|
private readonly clock: IClock,
|
|
55
56
|
private readonly metrics: Metrics | null = null,
|
|
56
57
|
private logger: Logger | null = null
|
|
@@ -92,7 +93,7 @@ export class SyncContributionAndProofPool {
|
|
|
92
93
|
|
|
93
94
|
// Reject ContributionAndProofs of previous slots
|
|
94
95
|
// for api ContributionAndProofs, we allow them to be added to the pool
|
|
95
|
-
if (!priority && slot < this.clock.slotWithPastTolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY)) {
|
|
96
|
+
if (!priority && slot < this.clock.slotWithPastTolerance(this.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000)) {
|
|
96
97
|
return InsertOutcome.Late;
|
|
97
98
|
}
|
|
98
99
|
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
ssz,
|
|
37
37
|
} from "@lodestar/types";
|
|
38
38
|
import {assert, toRootHex} from "@lodestar/utils";
|
|
39
|
-
import {MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC} from "../../constants/index.js";
|
|
40
39
|
import {sszDeserializeSingleAttestation} from "../../network/gossip/topic.js";
|
|
41
40
|
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
42
41
|
import {
|
|
@@ -570,8 +569,8 @@ async function validateAttestationNoSignatureCheck(
|
|
|
570
569
|
* Note: We do not queue future attestations for later processing
|
|
571
570
|
*/
|
|
572
571
|
export function verifyPropagationSlotRange(fork: ForkName, chain: IBeaconChain, attestationSlot: Slot): void {
|
|
573
|
-
// slot with future tolerance of
|
|
574
|
-
const latestPermissibleSlot = chain.clock.slotWithFutureTolerance(
|
|
572
|
+
// slot with future tolerance of MAXIMUM_GOSSIP_CLOCK_DISPARITY
|
|
573
|
+
const latestPermissibleSlot = chain.clock.slotWithFutureTolerance(chain.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000);
|
|
575
574
|
if (attestationSlot > latestPermissibleSlot) {
|
|
576
575
|
throw new AttestationError(GossipAction.IGNORE, {
|
|
577
576
|
code: AttestationErrorCode.FUTURE_SLOT,
|
|
@@ -586,9 +585,9 @@ export function verifyPropagationSlotRange(fork: ForkName, chain: IBeaconChain,
|
|
|
586
585
|
// see: https://github.com/ethereum/consensus-specs/pull/3360
|
|
587
586
|
if (ForkSeq[fork] < ForkSeq.deneb) {
|
|
588
587
|
const earliestPermissibleSlot = Math.max(
|
|
589
|
-
// slot with past tolerance of
|
|
590
|
-
|
|
591
|
-
|
|
588
|
+
// slot with past tolerance of MAXIMUM_GOSSIP_CLOCK_DISPARITY
|
|
589
|
+
chain.clock.slotWithPastTolerance(chain.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000) -
|
|
590
|
+
chain.config.ATTESTATION_PROPAGATION_SLOT_RANGE,
|
|
592
591
|
0
|
|
593
592
|
);
|
|
594
593
|
|
|
@@ -614,7 +613,7 @@ export function verifyPropagationSlotRange(fork: ForkName, chain: IBeaconChain,
|
|
|
614
613
|
|
|
615
614
|
// lower bound for previous epoch is same as epoch of earliestPermissibleSlot
|
|
616
615
|
const currentEpochWithPastTolerance = computeEpochAtSlot(
|
|
617
|
-
chain.clock.slotWithPastTolerance(
|
|
616
|
+
chain.clock.slotWithPastTolerance(chain.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000)
|
|
618
617
|
);
|
|
619
618
|
|
|
620
619
|
const earliestPermissiblePreviousEpoch = Math.max(currentEpochWithPastTolerance - 1, 0);
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
} from "@lodestar/state-transition";
|
|
12
12
|
import {SignedBeaconBlock, deneb} from "@lodestar/types";
|
|
13
13
|
import {sleep, toRootHex} from "@lodestar/utils";
|
|
14
|
-
import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js";
|
|
15
14
|
import {BlockErrorCode, BlockGossipError, GossipAction} from "../errors/index.js";
|
|
16
15
|
import {IBeaconChain} from "../interface.js";
|
|
17
16
|
import {RegenCaller} from "../regen/index.js";
|
|
@@ -179,7 +178,7 @@ export async function validateGossipBlock(
|
|
|
179
178
|
// gossip validation promise without any extra infrastructure.
|
|
180
179
|
// Do the sleep at the end, since regen and signature validation can already take longer than `msToBlockSlot`.
|
|
181
180
|
const msToBlockSlot = computeTimeAtSlot(config, blockSlot, chain.genesisTime) * 1000 - Date.now();
|
|
182
|
-
if (msToBlockSlot <= MAXIMUM_GOSSIP_CLOCK_DISPARITY && msToBlockSlot > 0) {
|
|
181
|
+
if (msToBlockSlot <= config.MAXIMUM_GOSSIP_CLOCK_DISPARITY && msToBlockSlot > 0) {
|
|
183
182
|
// If block is between 0 and 500 ms early, hold it in a promise. Equivalent to a pending queue.
|
|
184
183
|
await sleep(msToBlockSlot);
|
|
185
184
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {ChainConfig} from "@lodestar/config";
|
|
1
|
+
import {ChainConfig, ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {
|
|
3
3
|
KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH,
|
|
4
4
|
KZG_COMMITMENTS_SUBTREE_INDEX,
|
|
5
5
|
NUMBER_OF_COLUMNS,
|
|
6
6
|
} from "@lodestar/params";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
computeEpochAtSlot,
|
|
9
|
+
computeStartSlotAtEpoch,
|
|
10
|
+
getBlockHeaderProposerSignatureSet,
|
|
11
|
+
} from "@lodestar/state-transition";
|
|
8
12
|
import {Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
|
|
9
13
|
import {toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
10
14
|
import {Metrics} from "../../metrics/metrics.js";
|
|
@@ -29,7 +33,7 @@ export async function validateGossipDataColumnSidecar(
|
|
|
29
33
|
const blockHeader = dataColumnSidecar.signedBlockHeader.message;
|
|
30
34
|
|
|
31
35
|
// 1) [REJECT] The sidecar is valid as verified by verify_data_column_sidecar
|
|
32
|
-
verifyDataColumnSidecar(dataColumnSidecar);
|
|
36
|
+
verifyDataColumnSidecar(chain.config, dataColumnSidecar);
|
|
33
37
|
|
|
34
38
|
// 2) [REJECT] The sidecar is for the correct subnet -- i.e. compute_subnet_for_data_column_sidecar(sidecar.index) == subnet_id
|
|
35
39
|
if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
|
|
@@ -184,7 +188,7 @@ export async function validateGossipDataColumnSidecar(
|
|
|
184
188
|
* SPEC FUNCTION
|
|
185
189
|
* https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#verify_data_column_sidecar
|
|
186
190
|
*/
|
|
187
|
-
function verifyDataColumnSidecar(dataColumnSidecar: fulu.DataColumnSidecar): void {
|
|
191
|
+
function verifyDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: fulu.DataColumnSidecar): void {
|
|
188
192
|
if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
|
|
189
193
|
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
190
194
|
code: DataColumnSidecarErrorCode.INVALID_INDEX,
|
|
@@ -201,6 +205,19 @@ function verifyDataColumnSidecar(dataColumnSidecar: fulu.DataColumnSidecar): voi
|
|
|
201
205
|
});
|
|
202
206
|
}
|
|
203
207
|
|
|
208
|
+
const epoch = computeEpochAtSlot(dataColumnSidecar.signedBlockHeader.message.slot);
|
|
209
|
+
const maxBlobsPerBlock = config.getMaxBlobsPerBlock(epoch);
|
|
210
|
+
|
|
211
|
+
if (dataColumnSidecar.kzgCommitments.length > maxBlobsPerBlock) {
|
|
212
|
+
throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
|
|
213
|
+
code: DataColumnSidecarErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
214
|
+
slot: dataColumnSidecar.signedBlockHeader.message.slot,
|
|
215
|
+
columnIdx: dataColumnSidecar.index,
|
|
216
|
+
count: dataColumnSidecar.kzgCommitments.length,
|
|
217
|
+
limit: maxBlobsPerBlock,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
204
221
|
if (
|
|
205
222
|
dataColumnSidecar.column.length !== dataColumnSidecar.kzgCommitments.length ||
|
|
206
223
|
dataColumnSidecar.column.length !== dataColumnSidecar.kzgProofs.length
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {LightClientOptimisticUpdate} from "@lodestar/types";
|
|
3
|
-
import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js";
|
|
4
3
|
import {assertLightClientServer} from "../../node/utils/lightclient.js";
|
|
5
4
|
import {IClock} from "../../util/clock.js";
|
|
6
5
|
import {GossipAction} from "../errors/index.js";
|
|
@@ -64,5 +63,7 @@ export function updateReceivedTooEarly(
|
|
|
64
63
|
update: Pick<LightClientOptimisticUpdate, "signatureSlot">
|
|
65
64
|
): boolean {
|
|
66
65
|
const fork = config.getForkName(update.signatureSlot);
|
|
67
|
-
return
|
|
66
|
+
return (
|
|
67
|
+
clock.msFromSlot(update.signatureSlot) < config.getSyncMessageDueMs(fork) - config.MAXIMUM_GOSSIP_CLOCK_DISPARITY
|
|
68
|
+
);
|
|
68
69
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
VoluntaryExitValidity,
|
|
3
|
+
getVoluntaryExitSignatureSet,
|
|
4
|
+
getVoluntaryExitValidity,
|
|
5
|
+
} from "@lodestar/state-transition";
|
|
2
6
|
import {phase0} from "@lodestar/types";
|
|
3
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
GossipAction,
|
|
9
|
+
VoluntaryExitError,
|
|
10
|
+
VoluntaryExitErrorCode,
|
|
11
|
+
voluntaryExitValidityToErrorCode,
|
|
12
|
+
} from "../errors/index.js";
|
|
4
13
|
import {IBeaconChain} from "../index.js";
|
|
5
14
|
import {RegenCaller} from "../regen/index.js";
|
|
6
15
|
|
|
@@ -43,9 +52,10 @@ async function validateVoluntaryExit(
|
|
|
43
52
|
|
|
44
53
|
// [REJECT] All of the conditions within process_voluntary_exit pass validation.
|
|
45
54
|
// verifySignature = false, verified in batch below
|
|
46
|
-
|
|
55
|
+
const validity = getVoluntaryExitValidity(chain.config.getForkSeq(state.slot), state, voluntaryExit, false);
|
|
56
|
+
if (validity !== VoluntaryExitValidity.valid) {
|
|
47
57
|
throw new VoluntaryExitError(GossipAction.REJECT, {
|
|
48
|
-
code:
|
|
58
|
+
code: voluntaryExitValidityToErrorCode(validity),
|
|
49
59
|
});
|
|
50
60
|
}
|
|
51
61
|
|
|
@@ -7,9 +7,3 @@ export const ZERO_HASH = Buffer.alloc(32, 0);
|
|
|
7
7
|
export const ZERO_HASH_HEX = "0x" + "00".repeat(32);
|
|
8
8
|
export const EMPTY_SIGNATURE = Buffer.alloc(96, 0);
|
|
9
9
|
export const GRAFFITI_SIZE = 32;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The maximum milliseconds of clock disparity assumed between honest nodes.
|
|
13
|
-
*/
|
|
14
|
-
export const MAXIMUM_GOSSIP_CLOCK_DISPARITY = 500;
|
|
15
|
-
export const MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC = MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000;
|
package/src/constants/network.ts
CHANGED
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* For more info on some of these constants:
|
|
3
|
-
* https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#configuration
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Gossip constants
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The maximum number of slots during which an attestation can be propagated.
|
|
10
|
-
*/
|
|
11
|
-
export const ATTESTATION_PROPAGATION_SLOT_RANGE = 32;
|
|
12
|
-
|
|
13
|
-
/** The maximum allowed size of uncompressed gossip messages. */
|
|
14
|
-
export const GOSSIP_MAX_SIZE = 2 ** 20;
|
|
15
|
-
export const GOSSIP_MAX_SIZE_BELLATRIX = 10 * GOSSIP_MAX_SIZE;
|
|
16
|
-
/** The maximum allowed size of uncompressed req/resp chunked responses. */
|
|
17
|
-
export const MAX_CHUNK_SIZE = 2 ** 20;
|
|
18
|
-
export const MAX_CHUNK_SIZE_BELLATRIX = 10 * MAX_CHUNK_SIZE;
|
|
19
|
-
|
|
20
1
|
export enum GoodByeReasonCode {
|
|
21
2
|
INBOUND_DISCONNECT = -1,
|
|
22
3
|
CLIENT_SHUTDOWN = 1,
|