@lodestar/beacon-node 1.45.0-dev.b94232ff23 → 1.45.0-dev.bdb9aa149d
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/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +0 -1
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +46 -3
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +11 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +39 -3
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +9 -3
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/importBlock.js +1 -1
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -2
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +17 -17
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +1 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/interface.d.ts +1 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +2 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +3 -0
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
- package/lib/chain/options.d.ts +1 -0
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -0
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/seenCache/index.d.ts +0 -1
- package/lib/chain/seenCache/index.d.ts.map +1 -1
- package/lib/chain/seenCache/index.js +0 -1
- package/lib/chain/seenCache/index.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +3 -2
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +11 -3
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +0 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/sync/range/chain.d.ts +4 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +3 -3
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +10 -0
- package/lib/sync/range/range.js.map +1 -1
- package/lib/util/graffiti.d.ts +15 -0
- package/lib/util/graffiti.d.ts.map +1 -1
- package/lib/util/graffiti.js +55 -0
- package/lib/util/graffiti.js.map +1 -1
- package/package.json +14 -14
- package/src/api/impl/beacon/pool/index.ts +0 -1
- package/src/api/impl/beacon/state/index.ts +52 -1
- package/src/api/impl/beacon/state/utils.ts +57 -4
- package/src/api/impl/validator/index.ts +9 -3
- package/src/chain/blocks/importBlock.ts +1 -1
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +17 -17
- package/src/chain/chain.ts +0 -3
- package/src/chain/interface.ts +0 -2
- package/src/chain/opPools/proposerPreferencesPool.ts +5 -1
- package/src/chain/options.ts +2 -0
- package/src/chain/seenCache/index.ts +0 -1
- package/src/chain/stateCache/persistentCheckpointsCache.ts +3 -2
- package/src/chain/validation/proposerPreferences.ts +12 -3
- package/src/network/processor/gossipHandlers.ts +0 -1
- package/src/sync/range/chain.ts +4 -5
- package/src/sync/range/range.ts +10 -0
- package/src/util/graffiti.ts +78 -0
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +0 -16
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +0 -1
- package/lib/chain/seenCache/seenProposerPreferences.js +0 -26
- package/lib/chain/seenCache/seenProposerPreferences.js.map +0 -1
- package/src/chain/seenCache/seenProposerPreferences.ts +0 -32
|
@@ -8,28 +8,24 @@ import {ImportPayloadOpts} from "./types.js";
|
|
|
8
8
|
// TODO GLOAS: Set to be equal to DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES for now
|
|
9
9
|
const QUEUE_MAX_LENGTH = 16;
|
|
10
10
|
|
|
11
|
-
enum PayloadEnvelopeImportStatus {
|
|
12
|
-
queued = "queued",
|
|
13
|
-
importing = "importing",
|
|
14
|
-
imported = "imported",
|
|
15
|
-
}
|
|
16
|
-
|
|
17
11
|
/**
|
|
18
12
|
* PayloadEnvelopeProcessor processes payload envelope jobs in a queued fashion, one after the other.
|
|
19
13
|
*
|
|
20
14
|
* Jobs are enqueued only on envelope arrival (gossip or API). The envelope may reach us before
|
|
21
15
|
* the sampled data columns; importExecutionPayload awaits `verifyPayloadsDataAvailability`
|
|
22
16
|
* internally, so a queued job can pend for up to `PAYLOAD_DATA_AVAILABILITY_TIMEOUT` while
|
|
23
|
-
* waiting for columns. Duplicate triggers for the same payloadInput are deduped
|
|
17
|
+
* waiting for columns. Duplicate triggers for the same payloadInput are deduped by sharing the
|
|
18
|
+
* in-flight import promise: every caller observes the real import outcome. Resolving duplicates
|
|
19
|
+
* early instead would let BlockInputSync mark a still-pending payload as processed, re-queue it,
|
|
20
|
+
* and spin re-processing the same root until OOM while the import is blocked (e.g. EL syncing).
|
|
24
21
|
*/
|
|
25
22
|
export class PayloadEnvelopeProcessor {
|
|
26
23
|
readonly jobQueue: JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>;
|
|
27
|
-
private readonly
|
|
24
|
+
private readonly imports = new WeakMap<PayloadEnvelopeInput, Promise<void>>();
|
|
28
25
|
|
|
29
26
|
constructor(chain: BeaconChain, metrics: Metrics | null, signal: AbortSignal) {
|
|
30
27
|
this.jobQueue = new JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>(
|
|
31
28
|
(payloadInput, opts) => {
|
|
32
|
-
this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.importing);
|
|
33
29
|
return processExecutionPayload.call(chain, payloadInput, signal, opts);
|
|
34
30
|
},
|
|
35
31
|
{maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
|
|
@@ -38,24 +34,28 @@ export class PayloadEnvelopeProcessor {
|
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
async processPayloadEnvelopeJob(payloadInput: PayloadEnvelopeInput, opts: ImportPayloadOpts = {}): Promise<void> {
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
const existing = this.imports.get(payloadInput);
|
|
38
|
+
if (existing) {
|
|
39
|
+
return existing;
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
await this.jobQueue.waitForSpace();
|
|
46
43
|
|
|
47
44
|
// Re-check after await, as another call may have queued this payload.
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const queued = this.imports.get(payloadInput);
|
|
46
|
+
if (queued) {
|
|
47
|
+
return queued;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
this.
|
|
50
|
+
const importPromise = this.jobQueue.push(payloadInput, opts);
|
|
51
|
+
this.imports.set(payloadInput, importPromise);
|
|
53
52
|
|
|
54
53
|
try {
|
|
55
|
-
await
|
|
56
|
-
this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.imported);
|
|
54
|
+
await importPromise;
|
|
57
55
|
} catch (e) {
|
|
58
|
-
|
|
56
|
+
// Drop the failed import so a later attempt can retry once the failure cause is resolved
|
|
57
|
+
// (e.g. BLOCK_NOT_IN_FORK_CHOICE after the block lands in fork choice)
|
|
58
|
+
this.imports.delete(payloadInput);
|
|
59
59
|
throw e;
|
|
60
60
|
}
|
|
61
61
|
}
|
package/src/chain/chain.ts
CHANGED
|
@@ -107,7 +107,6 @@ import {
|
|
|
107
107
|
SeenExecutionPayloadBids,
|
|
108
108
|
SeenPayloadAttesters,
|
|
109
109
|
SeenPayloadEnvelopeInput,
|
|
110
|
-
SeenProposerPreferences,
|
|
111
110
|
SeenSyncCommitteeMessages,
|
|
112
111
|
} from "./seenCache/index.js";
|
|
113
112
|
import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
|
|
@@ -189,7 +188,6 @@ export class BeaconChain implements IBeaconChain {
|
|
|
189
188
|
readonly seenPayloadAttesters = new SeenPayloadAttesters();
|
|
190
189
|
readonly seenAggregatedAttestations: SeenAggregatedAttestations;
|
|
191
190
|
readonly seenExecutionPayloadBids = new SeenExecutionPayloadBids();
|
|
192
|
-
readonly seenProposerPreferences = new SeenProposerPreferences();
|
|
193
191
|
readonly seenBlockProposers = new SeenBlockProposers();
|
|
194
192
|
readonly seenSyncCommitteeMessages = new SeenSyncCommitteeMessages();
|
|
195
193
|
readonly seenContributionAndProof: SeenContributionAndProof;
|
|
@@ -1473,7 +1471,6 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1473
1471
|
this.payloadAttestationPool.prune(slot);
|
|
1474
1472
|
this.executionPayloadBidPool.prune(slot);
|
|
1475
1473
|
this.seenExecutionPayloadBids.prune(slot);
|
|
1476
|
-
this.seenProposerPreferences.prune(slot);
|
|
1477
1474
|
this.proposerPreferencesPool.prune(slot);
|
|
1478
1475
|
this.seenAttestationDatas.onSlot(slot);
|
|
1479
1476
|
this.reprocessController.onSlot(slot);
|
package/src/chain/interface.ts
CHANGED
|
@@ -61,7 +61,6 @@ import {
|
|
|
61
61
|
SeenContributionAndProof,
|
|
62
62
|
SeenExecutionPayloadBids,
|
|
63
63
|
SeenPayloadAttesters,
|
|
64
|
-
SeenProposerPreferences,
|
|
65
64
|
SeenSyncCommitteeMessages,
|
|
66
65
|
} from "./seenCache/index.js";
|
|
67
66
|
import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
|
|
@@ -133,7 +132,6 @@ export interface IBeaconChain {
|
|
|
133
132
|
readonly seenPayloadAttesters: SeenPayloadAttesters;
|
|
134
133
|
readonly seenAggregatedAttestations: SeenAggregatedAttestations;
|
|
135
134
|
readonly seenExecutionPayloadBids: SeenExecutionPayloadBids;
|
|
136
|
-
readonly seenProposerPreferences: SeenProposerPreferences;
|
|
137
135
|
readonly seenBlockProposers: SeenBlockProposers;
|
|
138
136
|
readonly seenSyncCommitteeMessages: SeenSyncCommitteeMessages;
|
|
139
137
|
readonly seenContributionAndProof: SeenContributionAndProof;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {RootHex, Slot, gloas} from "@lodestar/types";
|
|
1
|
+
import {RootHex, Slot, ValidatorIndex, gloas} from "@lodestar/types";
|
|
2
2
|
import {toRootHex} from "@lodestar/utils";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -22,6 +22,10 @@ export class ProposerPreferencesPool {
|
|
|
22
22
|
return this.bySlot.get(slot)?.get(dependentRootHex) ?? null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
isKnown(proposalSlot: Slot, dependentRoot: RootHex, validatorIndex: ValidatorIndex): boolean {
|
|
26
|
+
return this.get(proposalSlot, dependentRoot)?.message.validatorIndex === validatorIndex;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
add(signed: gloas.SignedProposerPreferences): void {
|
|
26
30
|
const {proposalSlot, dependentRoot} = signed.message;
|
|
27
31
|
const rootHex = toRootHex(dependentRoot);
|
package/src/chain/options.ts
CHANGED
|
@@ -35,6 +35,7 @@ export type IChainOptions = BlockProcessOpts &
|
|
|
35
35
|
persistOrphanedBlocksDir?: string;
|
|
36
36
|
skipCreateStateCacheIfAvailable?: boolean;
|
|
37
37
|
suggestedFeeRecipient: string;
|
|
38
|
+
graffitiAppend?: boolean;
|
|
38
39
|
maxSkipSlots?: number;
|
|
39
40
|
/** Ensure blobs returned by the execution engine are valid */
|
|
40
41
|
sanityCheckExecutionEngineBlobs?: boolean;
|
|
@@ -107,6 +108,7 @@ export const defaultChainOptions: IChainOptions = {
|
|
|
107
108
|
computeUnrealized: true,
|
|
108
109
|
fastConfirmation: false,
|
|
109
110
|
suggestedFeeRecipient: defaultValidatorOptions.suggestedFeeRecipient,
|
|
111
|
+
graffitiAppend: true,
|
|
110
112
|
serveHistoricalState: false,
|
|
111
113
|
assertCorrectProgressiveBalances: false,
|
|
112
114
|
archiveStateEpochFrequency: 1024,
|
|
@@ -5,4 +5,3 @@ export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
|
|
|
5
5
|
export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
|
|
6
6
|
export {SeenBlockInput} from "./seenGossipBlockInput.js";
|
|
7
7
|
export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
|
|
8
|
-
export {SeenProposerPreferences} from "./seenProposerPreferences.js";
|
|
@@ -331,8 +331,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
331
331
|
const key = toCacheKey(cpHex);
|
|
332
332
|
const cacheItem = this.cache.get(key);
|
|
333
333
|
this.metrics?.cpStateCache.adds.inc();
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
// keep an existing persistedKey (persisted or reloaded-in-memory); dropping it orphans the on-disk file
|
|
335
|
+
const persistedKey = cacheItem && (isPersistedCacheItem(cacheItem) ? cacheItem.value : cacheItem.persistedKey);
|
|
336
|
+
if (persistedKey !== undefined) {
|
|
336
337
|
// was persisted to disk, set back to memory
|
|
337
338
|
this.cache.set(key, {type: CacheItemType.inMemory, state, persistedKey});
|
|
338
339
|
this.logger.verbose("Added checkpoint state to memory but a persisted key existed", {
|
|
@@ -81,7 +81,7 @@ export async function validateGossipProposerPreferences(
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// [IGNORE] First valid message for (dependent_root, proposal_slot, validator_index).
|
|
84
|
-
if (chain.
|
|
84
|
+
if (chain.proposerPreferencesPool.isKnown(proposalSlot, dependentRootHex, validatorIndex)) {
|
|
85
85
|
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
86
86
|
code: ProposerPreferencesErrorCode.ALREADY_KNOWN,
|
|
87
87
|
proposalSlot,
|
|
@@ -105,6 +105,15 @@ export async function validateGossipProposerPreferences(
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
//
|
|
109
|
-
chain.
|
|
108
|
+
// Repeated check - deals with race-condition between preferences submissions
|
|
109
|
+
if (chain.proposerPreferencesPool.isKnown(proposalSlot, dependentRootHex, validatorIndex)) {
|
|
110
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
111
|
+
code: ProposerPreferencesErrorCode.ALREADY_KNOWN,
|
|
112
|
+
proposalSlot,
|
|
113
|
+
validatorIndex,
|
|
114
|
+
dependentRoot: dependentRootHex,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
chain.proposerPreferencesPool.add(signedProposerPreferences);
|
|
110
119
|
}
|
|
@@ -1273,7 +1273,6 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1273
1273
|
const signedProposerPreferences = sszDeserialize(topic, serializedData);
|
|
1274
1274
|
await validateGossipProposerPreferences(chain, signedProposerPreferences);
|
|
1275
1275
|
|
|
1276
|
-
chain.proposerPreferencesPool.add(signedProposerPreferences);
|
|
1277
1276
|
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1278
1277
|
version: ForkName.gloas,
|
|
1279
1278
|
data: signedProposerPreferences,
|
package/src/sync/range/chain.ts
CHANGED
|
@@ -186,10 +186,6 @@ export class SyncChain {
|
|
|
186
186
|
this.logger = logger;
|
|
187
187
|
this.logId = `${syncType}-${nextChainId++}`;
|
|
188
188
|
|
|
189
|
-
if (metrics) {
|
|
190
|
-
metrics.syncRange.headSyncPeers.addCollect(() => this.scrapeMetrics(metrics));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
189
|
// Trigger event on parent class
|
|
194
190
|
this.sync().then(
|
|
195
191
|
() => fns.onEnd(null, this.target),
|
|
@@ -775,7 +771,10 @@ export class SyncChain {
|
|
|
775
771
|
});
|
|
776
772
|
}
|
|
777
773
|
|
|
778
|
-
|
|
774
|
+
/**
|
|
775
|
+
* Called by `RangeSync`'s to avoid collecting metrics of removed chains.
|
|
776
|
+
*/
|
|
777
|
+
scrapeMetrics(metrics: Metrics): void {
|
|
779
778
|
const syncPeersMetric =
|
|
780
779
|
this.syncType === RangeSyncType.Finalized
|
|
781
780
|
? metrics.syncRange.finalizedSyncPeers
|
package/src/sync/range/range.ts
CHANGED
|
@@ -105,6 +105,16 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
105
105
|
|
|
106
106
|
if (metrics) {
|
|
107
107
|
metrics.syncStatus.addCollect(() => this.scrapeMetrics(metrics));
|
|
108
|
+
metrics.syncRange.headSyncPeers.addCollect(() => {
|
|
109
|
+
// Gauges retain their last set value, so a removed chain would keep reporting stale
|
|
110
|
+
// per-column peer counts (finalizedSyncPeers especially, as it is rarely recreated once
|
|
111
|
+
// synced)
|
|
112
|
+
metrics.syncRange.headSyncPeers.reset();
|
|
113
|
+
metrics.syncRange.finalizedSyncPeers.reset();
|
|
114
|
+
for (const syncChain of this.chains.values()) {
|
|
115
|
+
syncChain.scrapeMetrics(metrics);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
|
package/src/util/graffiti.ts
CHANGED
|
@@ -37,3 +37,81 @@ export function getDefaultGraffiti(
|
|
|
37
37
|
// No EL client info available. We still want to include CL info albeit not spec compliant
|
|
38
38
|
return `${consensusClientVersion.code}${consensusClientVersion.commit.slice(0, 4)}`;
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
function appendLongestFittingSuffix(userGraffiti: string, suffixes: string[]): string {
|
|
42
|
+
const userGraffitiBytes = Buffer.byteLength(userGraffiti, "utf8");
|
|
43
|
+
if (userGraffitiBytes >= GRAFFITI_SIZE) {
|
|
44
|
+
return userGraffiti;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const availableBytes = GRAFFITI_SIZE - userGraffitiBytes;
|
|
48
|
+
|
|
49
|
+
for (const suffix of suffixes) {
|
|
50
|
+
if (Buffer.byteLength(suffix, "utf8") <= availableBytes) {
|
|
51
|
+
return `${userGraffiti}${suffix}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return userGraffiti;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Appends the richest available client watermark that fits after user graffiti.
|
|
60
|
+
*
|
|
61
|
+
* Tiers are:
|
|
62
|
+
* - full EL/CL watermark, e.g. " BU9b0eLS80c2"
|
|
63
|
+
* - EL/CL client codes, e.g. " BULS"
|
|
64
|
+
* - CL client code, e.g. " LS"
|
|
65
|
+
*/
|
|
66
|
+
export function appendClientInfoToGraffiti(
|
|
67
|
+
userGraffiti: string,
|
|
68
|
+
consensusClientVersion: ClientVersion,
|
|
69
|
+
executionClientVersion: ClientVersion | null | undefined,
|
|
70
|
+
opts: {private?: boolean} = {}
|
|
71
|
+
): string {
|
|
72
|
+
if (opts.private) {
|
|
73
|
+
return userGraffiti;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Graffiti supplied via the beacon API is decoded from a fixed 32-byte field (see
|
|
77
|
+
// fromGraffitiHex) and arrives right-padded with NUL bytes. Trim only trailing padding
|
|
78
|
+
// NULs; a NUL that appears in the middle of the string is data, not padding.
|
|
79
|
+
let end = userGraffiti.length;
|
|
80
|
+
while (end > 0 && userGraffiti.charCodeAt(end - 1) === 0) {
|
|
81
|
+
end--;
|
|
82
|
+
}
|
|
83
|
+
const graffiti = userGraffiti.slice(0, end);
|
|
84
|
+
|
|
85
|
+
const fullClientInfo = getDefaultGraffiti(consensusClientVersion, executionClientVersion, {private: false});
|
|
86
|
+
if (graffiti.length === 0) {
|
|
87
|
+
return fullClientInfo;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const suffixes =
|
|
91
|
+
executionClientVersion != null
|
|
92
|
+
? [
|
|
93
|
+
` ${fullClientInfo}`,
|
|
94
|
+
` ${executionClientVersion.code}${consensusClientVersion.code}`,
|
|
95
|
+
` ${consensusClientVersion.code}`,
|
|
96
|
+
]
|
|
97
|
+
: [` ${fullClientInfo}`, ` ${consensusClientVersion.code}`];
|
|
98
|
+
|
|
99
|
+
return appendLongestFittingSuffix(graffiti, suffixes);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function getBlockGraffiti(
|
|
103
|
+
userGraffiti: string | undefined,
|
|
104
|
+
consensusClientVersion: ClientVersion,
|
|
105
|
+
executionClientVersion: ClientVersion | null | undefined,
|
|
106
|
+
opts: {private?: boolean; graffitiAppend?: boolean}
|
|
107
|
+
): string {
|
|
108
|
+
if (userGraffiti === undefined) {
|
|
109
|
+
return getDefaultGraffiti(consensusClientVersion, executionClientVersion, opts);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (opts.graffitiAppend === false) {
|
|
113
|
+
return userGraffiti;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return appendClientInfoToGraffiti(userGraffiti, consensusClientVersion, executionClientVersion, opts);
|
|
117
|
+
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { RootHex, Slot, ValidatorIndex } from "@lodestar/types";
|
|
2
|
-
/**
|
|
3
|
-
* Tracks signed proposer preferences we've already seen per (dependent_root, proposal_slot, validator_index).
|
|
4
|
-
*/
|
|
5
|
-
export declare class SeenProposerPreferences {
|
|
6
|
-
private readonly validatorByDependentRootBySlot;
|
|
7
|
-
isKnown(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): boolean;
|
|
8
|
-
add(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): void;
|
|
9
|
-
/**
|
|
10
|
-
* Entries are only load-bearing while `proposal_slot > current_slot`. Once the slot has
|
|
11
|
-
* passed the `[IGNORE] proposal_slot > current_slot` gossip rule takes over, so drop them
|
|
12
|
-
* on each slot tick.
|
|
13
|
-
*/
|
|
14
|
-
prune(currentSlot: Slot): void;
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=seenProposerPreferences.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seenProposerPreferences.d.ts","sourceRoot":"","sources":["../../../src/chain/seenCache/seenProposerPreferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAE,IAAI,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAG9D;;GAEG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAE7C;IAEF,OAAO,CAAC,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,GAAG,OAAO,CAE3F;IAED,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,GAAG,IAAI,CAEpF;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI,CAM7B;CACF"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { MapDef } from "@lodestar/utils";
|
|
2
|
-
/**
|
|
3
|
-
* Tracks signed proposer preferences we've already seen per (dependent_root, proposal_slot, validator_index).
|
|
4
|
-
*/
|
|
5
|
-
export class SeenProposerPreferences {
|
|
6
|
-
validatorByDependentRootBySlot = new MapDef(() => new Map());
|
|
7
|
-
isKnown(dependentRoot, proposalSlot, validatorIndex) {
|
|
8
|
-
return this.validatorByDependentRootBySlot.get(proposalSlot)?.get(dependentRoot) === validatorIndex;
|
|
9
|
-
}
|
|
10
|
-
add(dependentRoot, proposalSlot, validatorIndex) {
|
|
11
|
-
this.validatorByDependentRootBySlot.getOrDefault(proposalSlot).set(dependentRoot, validatorIndex);
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Entries are only load-bearing while `proposal_slot > current_slot`. Once the slot has
|
|
15
|
-
* passed the `[IGNORE] proposal_slot > current_slot` gossip rule takes over, so drop them
|
|
16
|
-
* on each slot tick.
|
|
17
|
-
*/
|
|
18
|
-
prune(currentSlot) {
|
|
19
|
-
for (const slot of this.validatorByDependentRootBySlot.keys()) {
|
|
20
|
-
if (slot < currentSlot) {
|
|
21
|
-
this.validatorByDependentRootBySlot.delete(slot);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=seenProposerPreferences.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seenProposerPreferences.js","sourceRoot":"","sources":["../../../src/chain/seenCache/seenProposerPreferences.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,iBAAiB,CAAC;AAEvC;;GAEG;AACH,MAAM,OAAO,uBAAuB;IACjB,8BAA8B,GAAG,IAAI,MAAM,CAC1D,GAAG,EAAE,CAAC,IAAI,GAAG,EAA2B,CACzC,CAAC;IAEF,OAAO,CAAC,aAAsB,EAAE,YAAkB,EAAE,cAA8B,EAAW;QAC3F,OAAO,IAAI,CAAC,8BAA8B,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,KAAK,cAAc,CAAC;IAAA,CACrG;IAED,GAAG,CAAC,aAAsB,EAAE,YAAkB,EAAE,cAA8B,EAAQ;QACpF,IAAI,CAAC,8BAA8B,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IAAA,CACnG;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAiB,EAAQ;QAC7B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,8BAA8B,CAAC,IAAI,EAAE,EAAE,CAAC;YAC9D,IAAI,IAAI,GAAG,WAAW,EAAE,CAAC;gBACvB,IAAI,CAAC,8BAA8B,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IAAA,CACF;CACF"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
2
|
-
import {MapDef} from "@lodestar/utils";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Tracks signed proposer preferences we've already seen per (dependent_root, proposal_slot, validator_index).
|
|
6
|
-
*/
|
|
7
|
-
export class SeenProposerPreferences {
|
|
8
|
-
private readonly validatorByDependentRootBySlot = new MapDef<Slot, Map<RootHex, ValidatorIndex>>(
|
|
9
|
-
() => new Map<RootHex, ValidatorIndex>()
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
isKnown(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): boolean {
|
|
13
|
-
return this.validatorByDependentRootBySlot.get(proposalSlot)?.get(dependentRoot) === validatorIndex;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
add(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): void {
|
|
17
|
-
this.validatorByDependentRootBySlot.getOrDefault(proposalSlot).set(dependentRoot, validatorIndex);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Entries are only load-bearing while `proposal_slot > current_slot`. Once the slot has
|
|
22
|
-
* passed the `[IGNORE] proposal_slot > current_slot` gossip rule takes over, so drop them
|
|
23
|
-
* on each slot tick.
|
|
24
|
-
*/
|
|
25
|
-
prune(currentSlot: Slot): void {
|
|
26
|
-
for (const slot of this.validatorByDependentRootBySlot.keys()) {
|
|
27
|
-
if (slot < currentSlot) {
|
|
28
|
-
this.validatorByDependentRootBySlot.delete(slot);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|