Skip to content

Commit c68bfb2

Browse files
nazarhussainnflaig
andauthored
refactor: introduce safe-block to fork-choice (#8618)
**Motivation** There is a concept documented in the specs called [safe-block](https://github.com/ethereum/consensus-specs/blob/master/fork_choice/safe-block.md). Wanted to introduce that concept in our codebase so upcoming feature of `fcr` have less invasive changes. **Description** - Expose functions `getSafeBeaconBlockRoot` and `getSafeExecutionBlockHash` from `fork-choice` package. - Update the usage of `safeBlock` to use those functions --------- Co-authored-by: Nico Flaig <nflaig@protonmail.com>
1 parent dcab624 commit c68bfb2

5 files changed

Lines changed: 34 additions & 3 deletions

File tree

packages/beacon-node/src/chain/blocks/importBlock.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ForkChoiceError,
77
ForkChoiceErrorCode,
88
NotReorgedReason,
9+
getSafeExecutionBlockHash,
910
} from "@lodestar/fork-choice";
1011
import {ForkPostAltair, ForkPostElectra, ForkSeq, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
1112
import {
@@ -394,7 +395,7 @@ export async function importBlock(
394395
* the current finalized block does not contain any execution payload at all (pre MERGE_EPOCH) or if it contains a
395396
* zero block hash (pre TTD)
396397
*/
397-
const safeBlockHash = this.forkChoice.getJustifiedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
398+
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
398399
const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
399400
if (headBlockHash !== ZERO_HASH_HEX) {
400401
this.executionEngine

packages/beacon-node/src/chain/prepareNextSlot.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {routes} from "@lodestar/api";
22
import {ChainForkConfig} from "@lodestar/config";
3+
import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
34
import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostElectra} from "@lodestar/params";
45
import {
56
BeaconStateElectra,
@@ -166,7 +167,7 @@ export class PrepareNextSlotScheduler {
166167
computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
167168
this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
168169

169-
const safeBlockHash = this.chain.forkChoice.getJustifiedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
170+
const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
170171
const finalizedBlockHash =
171172
this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
172173
// awaiting here instead of throwing an async call because there is no other task

packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {ChainForkConfig} from "@lodestar/config";
2+
import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
23
import {
34
ForkName,
45
ForkPostBellatrix,
@@ -191,7 +192,7 @@ export async function produceBlockBody<T extends BlockType>(
191192

192193
// We don't deal with blinded blocks, execution engine, blobs and execution requests post-gloas
193194
} else if (isForkPostBellatrix(fork)) {
194-
const safeBlockHash = this.forkChoice.getJustifiedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
195+
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
195196
const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
196197
const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
197198
const feeRecipientType = requestedFeeRecipient
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {ZERO_HASH_HEX} from "@lodestar/params";
2+
import {Root, RootHex} from "@lodestar/types";
3+
import {IForkChoice} from "./interface.js";
4+
5+
/**
6+
* Under honest majority and certain network synchronicity assumptions there exists a block
7+
* that is safe from re-orgs. Normally this block is pretty close to the head of canonical
8+
* chain which makes it valuable to expose a safe block to users.
9+
*
10+
* https://github.com/ethereum/consensus-specs/blob/v1.6.0/fork_choice/safe-block.md#get_safe_beacon_block_root
11+
*/
12+
export function getSafeBeaconBlockRoot(fc: IForkChoice): Root {
13+
return fc.getJustifiedCheckpoint().root;
14+
}
15+
16+
/**
17+
* Get execution payload hash for the safe block
18+
* This function assumes that safe block is post Bellatrix and function should not be called otherwise.
19+
*
20+
* As our existing usage is aligned with above condition so not adding fork-check inside this function
21+
*
22+
*
23+
* https://github.com/ethereum/consensus-specs/blob/v1.6.0/fork_choice/safe-block.md#get_safe_execution_block_hash
24+
*/
25+
export function getSafeExecutionBlockHash(forkChoice: IForkChoice): RootHex {
26+
return forkChoice.getJustifiedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
27+
}

packages/fork-choice/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export {
1515
NotReorgedReason,
1616
type PowBlockHex,
1717
} from "./forkChoice/interface.js";
18+
export * from "./forkChoice/safeBlocks.js";
1819
export {
1920
type CheckpointWithHex,
2021
ForkChoiceStore,

0 commit comments

Comments
 (0)