@lodestar/fork-choice 1.47.0-dev.f591cb177e → 1.48.0-dev.67344272c0
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/forkChoice/forkChoice.d.ts +41 -15
- package/lib/forkChoice/forkChoice.d.ts.map +1 -1
- package/lib/forkChoice/forkChoice.js +180 -50
- package/lib/forkChoice/forkChoice.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/protoArray/interface.d.ts +7 -5
- package/lib/protoArray/interface.d.ts.map +1 -1
- package/lib/protoArray/protoArray.d.ts +13 -4
- package/lib/protoArray/protoArray.d.ts.map +1 -1
- package/lib/protoArray/protoArray.js +54 -19
- package/lib/protoArray/protoArray.js.map +1 -1
- package/package.json +8 -8
- package/src/forkChoice/forkChoice.ts +225 -60
- package/src/index.ts +1 -1
- package/src/protoArray/interface.ts +12 -5
- package/src/protoArray/protoArray.ts +67 -24
|
@@ -180,7 +180,8 @@ export declare class ForkChoice implements IForkChoice {
|
|
|
180
180
|
* https://github.com/ethereum/consensus-specs/pull/3034 for info about proposer boost reorg
|
|
181
181
|
* This function should only be called during block proposal and only be called after `updateHead()` in `updateAndGetHead()`
|
|
182
182
|
*
|
|
183
|
-
*
|
|
183
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/phase0/fork-choice.md#get_proposer_head
|
|
184
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#modified-get_proposer_head
|
|
184
185
|
*/
|
|
185
186
|
getProposerHead(headBlock: ProtoBlock, secFromSlot: number, slot: Slot): {
|
|
186
187
|
proposerHead: ProtoBlock;
|
|
@@ -212,20 +213,12 @@ export declare class ForkChoice implements IForkChoice {
|
|
|
212
213
|
};
|
|
213
214
|
/** Very expensive function, iterates the entire ProtoArray. Called only in debug API */
|
|
214
215
|
getHeads(): ProtoBlock[];
|
|
215
|
-
/**
|
|
216
|
-
* weight is in EFFECTIVE_BALANCE_INCREMENTS not gwei.
|
|
217
|
-
* For compliance test use only
|
|
218
|
-
*/
|
|
216
|
+
/** Returns exact Gwei weights for the compliance test. */
|
|
219
217
|
getViableHeads(): {
|
|
220
218
|
root: RootHex;
|
|
221
219
|
payloadStatus: PayloadStatus;
|
|
222
|
-
weight:
|
|
220
|
+
weight: bigint;
|
|
223
221
|
}[];
|
|
224
|
-
/**
|
|
225
|
-
* The cached justified total active balance, in EFFECTIVE_BALANCE_INCREMENT units.
|
|
226
|
-
* For compliance test use only
|
|
227
|
-
*/
|
|
228
|
-
getJustifiedTotalActiveBalanceByIncrement(): number;
|
|
229
222
|
/** This is for the debug API only */
|
|
230
223
|
getAllNodes(): ProtoNode[];
|
|
231
224
|
getFinalizedCheckpoint(): CheckpointWithHex;
|
|
@@ -469,6 +462,38 @@ export declare class ForkChoice implements IForkChoice {
|
|
|
469
462
|
* Child class can overwrite this for testing purpose.
|
|
470
463
|
*/
|
|
471
464
|
protected isBlockTimely(block: BeaconBlock, blockDelaySec: number): boolean;
|
|
465
|
+
/**
|
|
466
|
+
* Return true if the block arrived before the PTC (payload-timeliness committee) deadline,
|
|
467
|
+
* ie. block_timeliness[PTC_TIMELINESS_INDEX]. should_apply_proposer_boost uses this as the
|
|
468
|
+
* definition of an "early" proposer equivocation: only a sibling seen by the PTC deadline
|
|
469
|
+
* proves the proposer equivocated soon enough that honest nodes could have withheld the boost.
|
|
470
|
+
*
|
|
471
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#modified-record_block_timeliness
|
|
472
|
+
*
|
|
473
|
+
* Child class can overwrite this for testing purpose.
|
|
474
|
+
*/
|
|
475
|
+
protected isBlockPtcTimely(block: BeaconBlock, blockDelaySec: number): boolean;
|
|
476
|
+
/**
|
|
477
|
+
* Determine whether proposer boost should be applied to `proposerBoostRoot`.
|
|
478
|
+
*
|
|
479
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#new-should_apply_proposer_boost
|
|
480
|
+
*
|
|
481
|
+
* Pre-gloas blocks always receive the boost (unconditional, backward compatible). For gloas
|
|
482
|
+
* blocks the boost is withheld when the parent is a weak block from the previous slot and the
|
|
483
|
+
* proposer of that parent equivocated (published another PTC-timely block at the same slot).
|
|
484
|
+
*/
|
|
485
|
+
private shouldApplyProposerBoost;
|
|
486
|
+
/**
|
|
487
|
+
* Return true if another block at the same slot from the same proposer is known to fork choice.
|
|
488
|
+
*
|
|
489
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/phase0/fork-choice.md#is_proposer_equivocation
|
|
490
|
+
*/
|
|
491
|
+
private isProposerEquivocation;
|
|
492
|
+
/**
|
|
493
|
+
* The proposer boost to apply to `proposerBoostRoot`, propagated up the branch by
|
|
494
|
+
* applyScoreChanges() together with the deltas.
|
|
495
|
+
*/
|
|
496
|
+
private getProposerBoost;
|
|
472
497
|
/**
|
|
473
498
|
* https://github.com/ethereum/consensus-specs/blob/v1.5.0/specs/phase0/fork-choice.md#is_proposing_on_time
|
|
474
499
|
*/
|
|
@@ -495,6 +520,8 @@ export declare class ForkChoice implements IForkChoice {
|
|
|
495
520
|
* May need the justified balances of:
|
|
496
521
|
* - unrealizedJustified: Already available in `CheckpointWithBalance`
|
|
497
522
|
* Since this balances are already available the getter is just `() => balances`, without cache interaction
|
|
523
|
+
*
|
|
524
|
+
* @returns Whether either checkpoint was updated.
|
|
498
525
|
*/
|
|
499
526
|
private updateCheckpoints;
|
|
500
527
|
/**
|
|
@@ -537,6 +564,8 @@ export declare class ForkChoice implements IForkChoice {
|
|
|
537
564
|
* Equivalent to:
|
|
538
565
|
*
|
|
539
566
|
* https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/fork-choice.md#on_tick
|
|
567
|
+
*
|
|
568
|
+
* @returns Whether an epoch-boundary checkpoint was updated.
|
|
540
569
|
*/
|
|
541
570
|
private onTick;
|
|
542
571
|
/**
|
|
@@ -546,11 +575,8 @@ export declare class ForkChoice implements IForkChoice {
|
|
|
546
575
|
*
|
|
547
576
|
*/
|
|
548
577
|
private getPreliminaryProposerHead;
|
|
578
|
+
/** Returns whether it recomputed the head, so the caller can avoid a redundant `updateHead()`. */
|
|
549
579
|
private runFastConfirmation;
|
|
550
580
|
private createFastConfirmationContext;
|
|
551
581
|
}
|
|
552
|
-
export declare function getCommitteeFraction(justifiedTotalActiveBalanceByIncrement: number, config: {
|
|
553
|
-
slotsPerEpoch: number;
|
|
554
|
-
committeePercent: number;
|
|
555
|
-
}): number;
|
|
556
582
|
//# sourceMappingURL=forkChoice.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forkChoice.d.ts","sourceRoot":"","sources":["../../src/forkChoice/forkChoice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"forkChoice.d.ts","sourceRoot":"","sources":["../../src/forkChoice/forkChoice.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH, isForkPostFulu, isForkPostGloas } from "@lodestar/params";
|
|
1
|
+
import { EFFECTIVE_BALANCE_INCREMENT, MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH, isForkPostFulu, isForkPostGloas, } from "@lodestar/params";
|
|
2
2
|
import { DataAvailabilityStatus, ZERO_HASH, computeEpochAtSlot, computeSlotsSinceEpochStart, computeStartSlotAtEpoch, getAttesterSlashableIndices, isExecutionBlockBodyType, isStatePostBellatrix, } from "@lodestar/state-transition";
|
|
3
3
|
import { isGloasBeaconBlock, ssz, } from "@lodestar/types";
|
|
4
4
|
import { MapDef, fromHex, toRootHex, withObservedDuration } from "@lodestar/utils";
|
|
@@ -9,6 +9,7 @@ import { ForkChoiceError, ForkChoiceErrorCode, InvalidAttestationCode, InvalidBl
|
|
|
9
9
|
import { FastConfirmationRule, FastConfirmationSteps, } from "./fastConfirmation/fastConfirmationRule.js";
|
|
10
10
|
import { AncestorStatus, NotReorgedReason, } from "./interface.js";
|
|
11
11
|
import { toCheckpointWithHex } from "./store.js";
|
|
12
|
+
const EFFECTIVE_BALANCE_INCREMENT_BIGINT = BigInt(EFFECTIVE_BALANCE_INCREMENT);
|
|
12
13
|
export var UpdateHeadOpt;
|
|
13
14
|
(function (UpdateHeadOpt) {
|
|
14
15
|
UpdateHeadOpt["GetCanonicalHead"] = "getCanonicalHead";
|
|
@@ -259,12 +260,22 @@ export class ForkChoice {
|
|
|
259
260
|
if (parentBlock === undefined) {
|
|
260
261
|
return { shouldOverrideFcu: false, reason: NotReorgedReason.ParentBlockNotAvailable };
|
|
261
262
|
}
|
|
263
|
+
const currentTimeOk = headBlock.slot === currentSlot ||
|
|
264
|
+
(proposalSlot === currentSlot && this.isProposingOnTime(secFromSlot, currentSlot));
|
|
265
|
+
// Mirror the proposer equivocation branch of getProposerHead(). The head slot's attestations are
|
|
266
|
+
// still queued at this point so the head is assumed weak, same as for the regular branch below.
|
|
267
|
+
if (currentTimeOk && this.isProposerEquivocation(headBlock)) {
|
|
268
|
+
this.logger?.verbose("Head proposer equivocated. Should override forkchoice update", {
|
|
269
|
+
blockRoot: headBlock.blockRoot,
|
|
270
|
+
slot: currentSlot,
|
|
271
|
+
proposerIndex: headBlock.proposerIndex,
|
|
272
|
+
});
|
|
273
|
+
return { shouldOverrideFcu: true, parentBlock };
|
|
274
|
+
}
|
|
262
275
|
const { prelimProposerHead, prelimNotReorgedReason } = this.getPreliminaryProposerHead(headBlock, parentBlock, proposalSlot);
|
|
263
276
|
if (prelimProposerHead === headBlock) {
|
|
264
277
|
return { shouldOverrideFcu: false, reason: prelimNotReorgedReason ?? NotReorgedReason.Unknown };
|
|
265
278
|
}
|
|
266
|
-
const currentTimeOk = headBlock.slot === currentSlot ||
|
|
267
|
-
(proposalSlot === currentSlot && this.isProposingOnTime(secFromSlot, currentSlot));
|
|
268
279
|
if (!currentTimeOk) {
|
|
269
280
|
return { shouldOverrideFcu: false, reason: NotReorgedReason.ReorgMoreThanOneSlot };
|
|
270
281
|
}
|
|
@@ -338,7 +349,8 @@ export class ForkChoice {
|
|
|
338
349
|
* https://github.com/ethereum/consensus-specs/pull/3034 for info about proposer boost reorg
|
|
339
350
|
* This function should only be called during block proposal and only be called after `updateHead()` in `updateAndGetHead()`
|
|
340
351
|
*
|
|
341
|
-
*
|
|
352
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/phase0/fork-choice.md#get_proposer_head
|
|
353
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#modified-get_proposer_head
|
|
342
354
|
*/
|
|
343
355
|
getProposerHead(headBlock, secFromSlot, slot) {
|
|
344
356
|
const isHeadTimely = headBlock.timeliness;
|
|
@@ -358,6 +370,24 @@ export class ForkChoice {
|
|
|
358
370
|
if (parentBlock === undefined) {
|
|
359
371
|
return { proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ParentBlockNotAvailable };
|
|
360
372
|
}
|
|
373
|
+
// Half of single_slot_reorg check in the spec is done in getPreliminaryProposerHead()
|
|
374
|
+
const currentTimeOk = headBlock.slot + 1 === slot;
|
|
375
|
+
const isProposerBoostWornOff = this.proposerBoostRoot !== headBlock.blockRoot;
|
|
376
|
+
// Re-org more aggressively if there is a proposer equivocation in the previous slot, skipping the
|
|
377
|
+
// regular reorg conditions. Any known equivocation counts here, timely or not.
|
|
378
|
+
if (currentTimeOk &&
|
|
379
|
+
isProposerBoostWornOff &&
|
|
380
|
+
this.isProposerEquivocation(headBlock) &&
|
|
381
|
+
this.isHeadWeak(headBlock.blockRoot)) {
|
|
382
|
+
this.logger?.verbose("Performing single-slot reorg to remove weak head of equivocating proposer", {
|
|
383
|
+
slot,
|
|
384
|
+
proposerHead: parentBlock.blockRoot,
|
|
385
|
+
weakHead: headBlock.blockRoot,
|
|
386
|
+
proposerIndex: headBlock.proposerIndex,
|
|
387
|
+
});
|
|
388
|
+
proposerHead = parentBlock;
|
|
389
|
+
return { proposerHead, isHeadTimely };
|
|
390
|
+
}
|
|
361
391
|
const { prelimProposerHead, prelimNotReorgedReason } = this.getPreliminaryProposerHead(headBlock, parentBlock, slot);
|
|
362
392
|
if (prelimProposerHead === headBlock && prelimNotReorgedReason !== undefined) {
|
|
363
393
|
return { proposerHead, isHeadTimely, notReorgedReason: prelimNotReorgedReason };
|
|
@@ -367,13 +397,10 @@ export class ForkChoice {
|
|
|
367
397
|
return { proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.NotProposingOnTime };
|
|
368
398
|
}
|
|
369
399
|
// No reorg if attempted reorg is more than a single slot
|
|
370
|
-
// Half of single_slot_reorg check in the spec is done in getPreliminaryProposerHead()
|
|
371
|
-
const currentTimeOk = headBlock.slot + 1 === slot;
|
|
372
400
|
if (!currentTimeOk) {
|
|
373
401
|
return { proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ReorgMoreThanOneSlot };
|
|
374
402
|
}
|
|
375
403
|
// No reorg if proposer boost is still in effect
|
|
376
|
-
const isProposerBoostWornOff = this.proposerBoostRoot !== headBlock.blockRoot;
|
|
377
404
|
if (!isProposerBoostWornOff) {
|
|
378
405
|
return { proposerHead, isHeadTimely, notReorgedReason: NotReorgedReason.ProposerBoostNotWornOff };
|
|
379
406
|
}
|
|
@@ -428,30 +455,45 @@ export class ForkChoice {
|
|
|
428
455
|
computeDeltasMetrics?.unchangedVoteValidators.set(unchangedVoteValidators);
|
|
429
456
|
computeDeltasMetrics?.newVoteValidators.set(newVoteValidators);
|
|
430
457
|
this.balances = newBalances;
|
|
431
|
-
/**
|
|
432
|
-
* The structure in line with deltas to propagate boost up the branch
|
|
433
|
-
* starting from the proposerIndex
|
|
434
|
-
*/
|
|
435
|
-
let proposerBoost = null;
|
|
436
|
-
if (this.opts?.proposerBoost && this.proposerBoostRoot) {
|
|
437
|
-
const proposerBoostScore = this.justifiedProposerBoostScore ??
|
|
438
|
-
getCommitteeFraction(this.fcStore.justified.totalBalance, {
|
|
439
|
-
slotsPerEpoch: SLOTS_PER_EPOCH,
|
|
440
|
-
committeePercent: this.config.PROPOSER_SCORE_BOOST,
|
|
441
|
-
});
|
|
442
|
-
proposerBoost = { root: this.proposerBoostRoot, score: proposerBoostScore };
|
|
443
|
-
this.justifiedProposerBoostScore = proposerBoostScore;
|
|
444
|
-
}
|
|
445
458
|
const currentSlot = this.fcStore.currentSlot;
|
|
446
|
-
|
|
447
|
-
attestationDeltas,
|
|
448
|
-
proposerBoost,
|
|
459
|
+
const checkpoints = {
|
|
449
460
|
justifiedEpoch: this.fcStore.justified.checkpoint.epoch,
|
|
450
461
|
justifiedRoot: this.fcStore.justified.checkpoint.rootHex,
|
|
451
462
|
finalizedEpoch: this.fcStore.finalizedCheckpoint.epoch,
|
|
452
463
|
finalizedRoot: this.fcStore.finalizedCheckpoint.rootHex,
|
|
453
464
|
currentSlot,
|
|
454
|
-
}
|
|
465
|
+
};
|
|
466
|
+
const boostedBlock = this.opts?.proposerBoost && this.proposerBoostRoot ? this.getBlockHexDefaultStatus(this.proposerBoostRoot) : null;
|
|
467
|
+
if (boostedBlock && isGloasBlock(boostedBlock)) {
|
|
468
|
+
// should_apply_proposer_boost judges the parent against the attestations known to the store,
|
|
469
|
+
// via is_head_weak (which also assumes equivocators' votes were already discounted before
|
|
470
|
+
// their balance is added back). Apply the attestation deltas first so the decision reads
|
|
471
|
+
// post-delta scores, then apply the boost in a second pass.
|
|
472
|
+
// TODO GLOAS: applyScoreChanges() updates weights and best child/descendant in one call;
|
|
473
|
+
// splitting them would let the two passes update weights and recompute best child/descendant
|
|
474
|
+
// once at the end.
|
|
475
|
+
// https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#new-should_apply_proposer_boost
|
|
476
|
+
this.protoArray.applyScoreChanges({ attestationDeltas, proposerBoost: null, ...checkpoints });
|
|
477
|
+
const proposerBoost = this.shouldApplyProposerBoost() ? this.getProposerBoost() : null;
|
|
478
|
+
// The first pass already rolled back the previous boost and left a coherent tree, so a
|
|
479
|
+
// withheld boost needs no second pass
|
|
480
|
+
if (proposerBoost !== null) {
|
|
481
|
+
this.protoArray.applyScoreChanges({
|
|
482
|
+
attestationDeltas: new Array(this.protoArray.nodes.length).fill(0),
|
|
483
|
+
proposerBoost,
|
|
484
|
+
...checkpoints,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
// Pre-gloas the boost is unconditional, so attestation deltas and boost deltas can propagate
|
|
490
|
+
// up the branch in a single pass
|
|
491
|
+
this.protoArray.applyScoreChanges({
|
|
492
|
+
attestationDeltas,
|
|
493
|
+
proposerBoost: boostedBlock ? this.getProposerBoost() : null,
|
|
494
|
+
...checkpoints,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
455
497
|
// findHead returns the ProtoNode representing the head
|
|
456
498
|
const head = this.protoArray.findHead(this.fcStore.justified.checkpoint.rootHex, currentSlot);
|
|
457
499
|
this.head = head;
|
|
@@ -472,20 +514,10 @@ export class ForkChoice {
|
|
|
472
514
|
getHeads() {
|
|
473
515
|
return this.protoArray.nodes.filter((node) => node.bestChild === undefined);
|
|
474
516
|
}
|
|
475
|
-
/**
|
|
476
|
-
* weight is in EFFECTIVE_BALANCE_INCREMENTS not gwei.
|
|
477
|
-
* For compliance test use only
|
|
478
|
-
*/
|
|
517
|
+
/** Returns exact Gwei weights for the compliance test. */
|
|
479
518
|
getViableHeads() {
|
|
480
519
|
return this.protoArray.getViableHeads(this.fcStore.currentSlot);
|
|
481
520
|
}
|
|
482
|
-
/**
|
|
483
|
-
* The cached justified total active balance, in EFFECTIVE_BALANCE_INCREMENT units.
|
|
484
|
-
* For compliance test use only
|
|
485
|
-
*/
|
|
486
|
-
getJustifiedTotalActiveBalanceByIncrement() {
|
|
487
|
-
return this.fcStore.justified.totalBalance;
|
|
488
|
-
}
|
|
489
521
|
/** This is for the debug API only */
|
|
490
522
|
getAllNodes() {
|
|
491
523
|
return this.protoArray.nodes;
|
|
@@ -642,6 +674,8 @@ export class ForkChoice {
|
|
|
642
674
|
targetRoot: toRootHex(targetRoot),
|
|
643
675
|
stateRoot: toRootHex(block.stateRoot),
|
|
644
676
|
timeliness: isTimely,
|
|
677
|
+
ptcTimeliness: this.isBlockPtcTimely(block, blockDelaySec),
|
|
678
|
+
proposerIndex: block.proposerIndex,
|
|
645
679
|
justifiedEpoch: stateJustifiedEpoch,
|
|
646
680
|
justifiedRoot: toRootHex(state.currentJustifiedCheckpoint.root),
|
|
647
681
|
finalizedEpoch: finalizedCheckpoint.epoch,
|
|
@@ -851,11 +885,18 @@ export class ForkChoice {
|
|
|
851
885
|
while (this.fcStore.currentSlot < currentSlot) {
|
|
852
886
|
const previousSlot = this.fcStore.currentSlot;
|
|
853
887
|
// Note: we are relying upon `onTick` to update `fcStore.time` to ensure we don't get stuck in a loop.
|
|
854
|
-
this.onTick(previousSlot + 1);
|
|
888
|
+
const didUpdateCheckpoints = this.onTick(previousSlot + 1);
|
|
855
889
|
this.queuedAttestationsPreviousSlot = 0;
|
|
856
890
|
// Process any attestations that might now be eligible before running FCR for this slot.
|
|
857
891
|
this.processAttestationQueue();
|
|
858
|
-
this.runFastConfirmation();
|
|
892
|
+
const didRecomputeHead = this.runFastConfirmation();
|
|
893
|
+
// An epoch-boundary checkpoint pull-up can move the head's dependent root and stale the cached
|
|
894
|
+
// head before block 0 of the new epoch is imported, making isProposerBoostSameDependentRoot()
|
|
895
|
+
// wrong for that block. Recompute the head so it reflects the new checkpoint and the queued
|
|
896
|
+
// votes — unless fast confirmation already did, to avoid a redundant head calculation.
|
|
897
|
+
if (didUpdateCheckpoints && !didRecomputeHead) {
|
|
898
|
+
this.updateHead();
|
|
899
|
+
}
|
|
859
900
|
this.validatedAttestationDatas = new Set();
|
|
860
901
|
}
|
|
861
902
|
}
|
|
@@ -1290,7 +1331,8 @@ export class ForkChoice {
|
|
|
1290
1331
|
// Only ever called on a block already in fork choice, so a miss is a broken invariant.
|
|
1291
1332
|
const node = this.protoArray.getNodeDefaultStatus(blockRoot);
|
|
1292
1333
|
if (node === undefined) {
|
|
1293
|
-
// this is called for head
|
|
1334
|
+
// this is called for head or the boosted block's parent, both of which should always be
|
|
1335
|
+
// in forkchoice, otherwise we have a serious error
|
|
1294
1336
|
throw new ForkChoiceError({ code: ForkChoiceErrorCode.MISSING_PROTO_ARRAY_BLOCK, root: blockRoot });
|
|
1295
1337
|
}
|
|
1296
1338
|
const reorgThreshold = getCommitteeFraction(this.fcStore.justified.totalBalance, {
|
|
@@ -1306,7 +1348,7 @@ export class ForkChoice {
|
|
|
1306
1348
|
// always 0. Return before fetching the state and walking the block's committees.
|
|
1307
1349
|
if (equivocatingIndices.size > 0) {
|
|
1308
1350
|
const state = this.fcStore.stateGetter({ stateRoot: node.stateRoot });
|
|
1309
|
-
// Only ever called on the head, so the state is always cached.
|
|
1351
|
+
// Only ever called on the head or the boosted block's parent, so the state is always cached.
|
|
1310
1352
|
// A miss is a broken invariant, not a recoverable state.
|
|
1311
1353
|
if (state === null) {
|
|
1312
1354
|
throw new ForkChoiceError({
|
|
@@ -1325,7 +1367,7 @@ export class ForkChoice {
|
|
|
1325
1367
|
// the justified state) - fall back to the head state's effective balance
|
|
1326
1368
|
balance = state.effectiveBalanceIncrements[validatorIndex];
|
|
1327
1369
|
}
|
|
1328
|
-
headWeight += balance;
|
|
1370
|
+
headWeight += BigInt(balance) * EFFECTIVE_BALANCE_INCREMENT_BIGINT;
|
|
1329
1371
|
}
|
|
1330
1372
|
}
|
|
1331
1373
|
}
|
|
@@ -1362,6 +1404,83 @@ export class ForkChoice {
|
|
|
1362
1404
|
const isBeforeLateBlockCutoff = blockDelaySec * 1000 < this.config.getAttestationDueMs(fork);
|
|
1363
1405
|
return this.fcStore.currentSlot === block.slot && isBeforeLateBlockCutoff;
|
|
1364
1406
|
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Return true if the block arrived before the PTC (payload-timeliness committee) deadline,
|
|
1409
|
+
* ie. block_timeliness[PTC_TIMELINESS_INDEX]. should_apply_proposer_boost uses this as the
|
|
1410
|
+
* definition of an "early" proposer equivocation: only a sibling seen by the PTC deadline
|
|
1411
|
+
* proves the proposer equivocated soon enough that honest nodes could have withheld the boost.
|
|
1412
|
+
*
|
|
1413
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#modified-record_block_timeliness
|
|
1414
|
+
*
|
|
1415
|
+
* Child class can overwrite this for testing purpose.
|
|
1416
|
+
*/
|
|
1417
|
+
isBlockPtcTimely(block, blockDelaySec) {
|
|
1418
|
+
const ptcThresholdMs = this.config.getSlotComponentDurationMs(this.config.PAYLOAD_ATTESTATION_DUE_BPS);
|
|
1419
|
+
return this.fcStore.currentSlot === block.slot && blockDelaySec * 1000 < ptcThresholdMs;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Determine whether proposer boost should be applied to `proposerBoostRoot`.
|
|
1423
|
+
*
|
|
1424
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/gloas/fork-choice.md#new-should_apply_proposer_boost
|
|
1425
|
+
*
|
|
1426
|
+
* Pre-gloas blocks always receive the boost (unconditional, backward compatible). For gloas
|
|
1427
|
+
* blocks the boost is withheld when the parent is a weak block from the previous slot and the
|
|
1428
|
+
* proposer of that parent equivocated (published another PTC-timely block at the same slot).
|
|
1429
|
+
*/
|
|
1430
|
+
shouldApplyProposerBoost() {
|
|
1431
|
+
if (!this.proposerBoostRoot) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
const boostedBlock = this.getBlockHexDefaultStatus(this.proposerBoostRoot);
|
|
1435
|
+
// Pre-gloas blocks always get boost
|
|
1436
|
+
if (!boostedBlock || !isGloasBlock(boostedBlock)) {
|
|
1437
|
+
return true;
|
|
1438
|
+
}
|
|
1439
|
+
const parentBlock = this.getBlockHexDefaultStatus(boostedBlock.parentRoot);
|
|
1440
|
+
if (!parentBlock) {
|
|
1441
|
+
return true;
|
|
1442
|
+
}
|
|
1443
|
+
// Apply proposer boost if parent is not from the previous slot
|
|
1444
|
+
if (parentBlock.slot + 1 < boostedBlock.slot) {
|
|
1445
|
+
return true;
|
|
1446
|
+
}
|
|
1447
|
+
// Apply proposer boost if parent is not weak
|
|
1448
|
+
if (!this.isHeadWeak(parentBlock.blockRoot)) {
|
|
1449
|
+
return true;
|
|
1450
|
+
}
|
|
1451
|
+
// Parent is weak and from the previous slot: apply boost only if there are no early
|
|
1452
|
+
// equivocations, ie. no other PTC-timely block at the parent's slot from the same proposer.
|
|
1453
|
+
return !this.protoArray.hasEquivocatingBlock(parentBlock.proposerIndex, parentBlock.slot, parentBlock.blockRoot,
|
|
1454
|
+
// Only a sibling seen before the PTC deadline counts. A late released one might not have been
|
|
1455
|
+
// seen by the proposer, so it cannot be expected to reorg it and is not denied the boost for it.
|
|
1456
|
+
true);
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Return true if another block at the same slot from the same proposer is known to fork choice.
|
|
1460
|
+
*
|
|
1461
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.14/specs/phase0/fork-choice.md#is_proposer_equivocation
|
|
1462
|
+
*/
|
|
1463
|
+
isProposerEquivocation(block) {
|
|
1464
|
+
// Any known sibling counts, timely or not. Timeliness only matters for withholding the boost from
|
|
1465
|
+
// the next proposer, the reorg itself is safe to attempt whenever the equivocation is visible.
|
|
1466
|
+
return this.protoArray.hasEquivocatingBlock(block.proposerIndex, block.slot, block.blockRoot, false);
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* The proposer boost to apply to `proposerBoostRoot`, propagated up the branch by
|
|
1470
|
+
* applyScoreChanges() together with the deltas.
|
|
1471
|
+
*/
|
|
1472
|
+
getProposerBoost() {
|
|
1473
|
+
if (!this.proposerBoostRoot) {
|
|
1474
|
+
return null;
|
|
1475
|
+
}
|
|
1476
|
+
const proposerBoostScore = this.justifiedProposerBoostScore ??
|
|
1477
|
+
getCommitteeFraction(this.fcStore.justified.totalBalance, {
|
|
1478
|
+
slotsPerEpoch: SLOTS_PER_EPOCH,
|
|
1479
|
+
committeePercent: this.config.PROPOSER_SCORE_BOOST,
|
|
1480
|
+
});
|
|
1481
|
+
this.justifiedProposerBoostScore = proposerBoostScore;
|
|
1482
|
+
return { root: this.proposerBoostRoot, score: proposerBoostScore };
|
|
1483
|
+
}
|
|
1365
1484
|
/**
|
|
1366
1485
|
* https://github.com/ethereum/consensus-specs/blob/v1.5.0/specs/phase0/fork-choice.md#is_proposing_on_time
|
|
1367
1486
|
*/
|
|
@@ -1404,18 +1523,24 @@ export class ForkChoice {
|
|
|
1404
1523
|
* May need the justified balances of:
|
|
1405
1524
|
* - unrealizedJustified: Already available in `CheckpointWithBalance`
|
|
1406
1525
|
* Since this balances are already available the getter is just `() => balances`, without cache interaction
|
|
1526
|
+
*
|
|
1527
|
+
* @returns Whether either checkpoint was updated.
|
|
1407
1528
|
*/
|
|
1408
1529
|
updateCheckpoints(justifiedCheckpoint, finalizedCheckpoint, getJustifiedBalances) {
|
|
1530
|
+
let updated = false;
|
|
1409
1531
|
// Update justified checkpoint.
|
|
1410
1532
|
if (justifiedCheckpoint.epoch > this.fcStore.justified.checkpoint.epoch) {
|
|
1411
1533
|
this.fcStore.justified = { checkpoint: justifiedCheckpoint, balances: getJustifiedBalances() };
|
|
1412
1534
|
this.justifiedProposerBoostScore = null;
|
|
1535
|
+
updated = true;
|
|
1413
1536
|
}
|
|
1414
1537
|
// Update finalized checkpoint.
|
|
1415
1538
|
if (finalizedCheckpoint.epoch > this.fcStore.finalizedCheckpoint.epoch) {
|
|
1416
1539
|
this.fcStore.finalizedCheckpoint = finalizedCheckpoint;
|
|
1417
1540
|
this.justifiedProposerBoostScore = null;
|
|
1541
|
+
updated = true;
|
|
1418
1542
|
}
|
|
1543
|
+
return updated;
|
|
1419
1544
|
}
|
|
1420
1545
|
/**
|
|
1421
1546
|
* Update unrealized checkpoints in store if necessary
|
|
@@ -1659,6 +1784,8 @@ export class ForkChoice {
|
|
|
1659
1784
|
* Equivalent to:
|
|
1660
1785
|
*
|
|
1661
1786
|
* https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/fork-choice.md#on_tick
|
|
1787
|
+
*
|
|
1788
|
+
* @returns Whether an epoch-boundary checkpoint was updated.
|
|
1662
1789
|
*/
|
|
1663
1790
|
onTick(time) {
|
|
1664
1791
|
const previousSlot = this.fcStore.currentSlot;
|
|
@@ -1678,10 +1805,10 @@ export class ForkChoice {
|
|
|
1678
1805
|
}
|
|
1679
1806
|
// Not a new epoch, return.
|
|
1680
1807
|
if (computeSlotsSinceEpochStart(time) !== 0) {
|
|
1681
|
-
return;
|
|
1808
|
+
return false;
|
|
1682
1809
|
}
|
|
1683
|
-
// If a new epoch, pull-up justification and finalization from previous epoch
|
|
1684
|
-
this.updateCheckpoints(this.fcStore.unrealizedJustified.checkpoint, this.fcStore.unrealizedFinalizedCheckpoint, () => this.fcStore.unrealizedJustified.balances);
|
|
1810
|
+
// If a new epoch, pull-up justification and finalization from previous epoch.
|
|
1811
|
+
return this.updateCheckpoints(this.fcStore.unrealizedJustified.checkpoint, this.fcStore.unrealizedFinalizedCheckpoint, () => this.fcStore.unrealizedJustified.balances);
|
|
1685
1812
|
}
|
|
1686
1813
|
/**
|
|
1687
1814
|
*
|
|
@@ -1724,11 +1851,12 @@ export class ForkChoice {
|
|
|
1724
1851
|
prelimProposerHead = parentBlock;
|
|
1725
1852
|
return { prelimProposerHead };
|
|
1726
1853
|
}
|
|
1854
|
+
/** Returns whether it recomputed the head, so the caller can avoid a redundant `updateHead()`. */
|
|
1727
1855
|
runFastConfirmation() {
|
|
1728
1856
|
const fastConfirmationRule = this.fastConfirmationRule;
|
|
1729
1857
|
const fastConfirmationContext = this.fastConfirmationContext;
|
|
1730
1858
|
if (!fastConfirmationRule || !fastConfirmationContext)
|
|
1731
|
-
return;
|
|
1859
|
+
return false;
|
|
1732
1860
|
if (this.fastConfirmationPaused) {
|
|
1733
1861
|
// Keep consumers on a safe, available root while the rule is paused
|
|
1734
1862
|
this.fcStore.confirmedRoot = this.fcStore.finalizedCheckpoint.rootHex;
|
|
@@ -1739,7 +1867,7 @@ export class ForkChoice {
|
|
|
1739
1867
|
// Runs outside the timed try/catch below; a throw would escape to the clock listener
|
|
1740
1868
|
this.logger?.debug("Fast confirmation notify failed", { slot: this.fcStore.currentSlot }, err);
|
|
1741
1869
|
}
|
|
1742
|
-
return;
|
|
1870
|
+
return false;
|
|
1743
1871
|
}
|
|
1744
1872
|
withObservedDuration(this.metrics?.fastConfirmation.totalDuration.startTimer(), () => {
|
|
1745
1873
|
try {
|
|
@@ -1754,6 +1882,7 @@ export class ForkChoice {
|
|
|
1754
1882
|
this.logger?.debug("Fast confirmation failed", { slot: this.fcStore.currentSlot, head: this.head.blockRoot, confirmedRoot: this.fcStore.confirmedRoot }, err);
|
|
1755
1883
|
}
|
|
1756
1884
|
});
|
|
1885
|
+
return true;
|
|
1757
1886
|
}
|
|
1758
1887
|
createFastConfirmationContext() {
|
|
1759
1888
|
const confirmationByzantineThreshold = this.config.CONFIRMATION_BYZANTINE_THRESHOLD;
|
|
@@ -1804,10 +1933,11 @@ export class ForkChoice {
|
|
|
1804
1933
|
};
|
|
1805
1934
|
}
|
|
1806
1935
|
}
|
|
1807
|
-
//
|
|
1936
|
+
// https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/phase0/fork-choice.md#calculate_committee_fraction
|
|
1808
1937
|
// Calculates proposer boost score when committeePercent = config.PROPOSER_SCORE_BOOST
|
|
1809
|
-
|
|
1810
|
-
const
|
|
1811
|
-
|
|
1938
|
+
function getCommitteeFraction(justifiedTotalActiveBalanceByIncrement, config) {
|
|
1939
|
+
const committeeWeightGwei = (BigInt(justifiedTotalActiveBalanceByIncrement) * EFFECTIVE_BALANCE_INCREMENT_BIGINT) /
|
|
1940
|
+
BigInt(config.slotsPerEpoch);
|
|
1941
|
+
return (committeeWeightGwei * BigInt(config.committeePercent)) / 100n;
|
|
1812
1942
|
}
|
|
1813
1943
|
//# sourceMappingURL=forkChoice.js.map
|