Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -739,13 +739,7 @@ const forkChoiceTest =
(name.includes("simple_attempted_reorg_without_enough_ffg_votes") ||
name.includes("include_votes_another_empty_chain_with_enough_ffg_votes_current_epoch") ||
name.includes("include_votes_another_empty_chain_with_enough_ffg_votes_previous_epoch") ||
name.includes("include_votes_another_empty_chain_without_enough_ffg_votes_current_epoch"))) ||
// TODO: re-enable after "apply proposer boost if dependent roots match" (consensus-specs #5306)
// is implemented. New behavior in v1.7.0-alpha.9; Lodestar still applies the boost
// unconditionally. Only the altair vectors exercise the changed condition (other forks pass).
name.endsWith("altair/fork_choice/on_block/pyspec_tests/justified_update_always_if_better") ||
name.endsWith("altair/fork_choice/on_block/pyspec_tests/justified_update_not_realized_finality") ||
name.endsWith("altair/fork_choice/get_head/pyspec_tests/voting_source_beyond_two_epoch"),
name.includes("include_votes_another_empty_chain_without_enough_ffg_votes_current_epoch"))),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ensi321 do you know what's missing to pass the remaining tests?

},
};
};
Expand Down
33 changes: 31 additions & 2 deletions packages/fork-choice/src/forkChoice/forkChoice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ChainForkConfig} from "@lodestar/config";
import {SLOTS_PER_EPOCH} from "@lodestar/params";
import {MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
import {
DataAvailabilityStatus,
EffectiveBalanceIncrements,
Expand Down Expand Up @@ -707,7 +707,8 @@ export class ForkChoice implements IForkChoice {
// only boost the first block we see
this.proposerBoostRoot === null &&
expectedProposerIndex !== null &&
block.proposerIndex === expectedProposerIndex
block.proposerIndex === expectedProposerIndex &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we still checking the proposer index, this should no longer be required, and allows us to remove some code we added in #9313

@ensi321 any reason you kept the index check?

this.isProposerBoostSameDependentRoot(this.head.blockRoot, parentRootHex)
) {
this.proposerBoostRoot = blockRootHex;
}
Expand Down Expand Up @@ -1494,6 +1495,34 @@ export class ForkChoice implements IForkChoice {
throw Error(`Not found dependent root for block slot ${block.slot}, epoch difference ${epochDifference}`);
}

/**
* Spec: phase0/fork-choice.md#update_proposer_boost_root (`is_same_dependent_root` condition,
* consensus-specs #5306). Proposer boost is only granted when the imported block shares the same

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consensus-specs #5306 we need to avoid these kind of reference imo, either add a full url or no reference at all

* proposer-shuffling dependent root for the current epoch as the canonical head computed before
* the block was imported. This withholds the boost from a block built on a different shuffling
* branch than the head.
*
* The block is not yet in the proto-array when this runs, so its dependent root is traced from
* its parent
*/
private isProposerBoostSameDependentRoot(headRootHex: RootHex, blockParentRootHex: RootHex): boolean {
const epoch = computeEpochAtSlot(this.fcStore.currentSlot);
// Genesis block parent
if (epoch <= MIN_SEED_LOOKAHEAD) {
return true;
}

const dependentSlot = computeStartSlotAtEpoch(epoch - MIN_SEED_LOOKAHEAD) - 1;
const headDependentRoot = this.protoArray.getAncestorOrNull(headRootHex, dependentSlot)?.blockRoot;
const blockDependentRoot = this.protoArray.getAncestorOrNull(blockParentRootHex, dependentSlot)?.blockRoot;
// On lookup failure, we lean on the conservative side and withold the boost
if (headDependentRoot === undefined || blockDependentRoot === undefined) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this happens only when the ancestor gets pruned. Not sure if we return true or false in this case. I think either is fine. Any thought? @twoeths

return false;
}
Comment thread
ensi321 marked this conversation as resolved.

return headDependentRoot === blockDependentRoot;
}

/**
* Return true if the block is timely for the current slot.
* Child class can overwrite this for testing purpose.
Expand Down
Loading