Skip to content

Commit

Permalink
Add and heartbeat to engine exchangeTransitionConfigurationV1 method (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
g11tech authored Aug 14, 2022
1 parent c2d3aa9 commit 1778fc4
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
36 changes: 36 additions & 0 deletions packages/beacon-node/src/chain/prepareNextSlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {Slot} from "@lodestar/types";
import {ILogger, sleep} from "@lodestar/utils";
import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
import {IMetrics} from "../metrics/index.js";
import {bytesToData, numToQuantity} from "../eth1/provider/utils.js";
import {TransitionConfigurationV1} from "../execution/engine/interface.js";
import {ChainEvent} from "./emitter.js";
import {prepareExecutionPayload} from "./factory/block/body.js";
import {IBeaconChain} from "./interface.js";
Expand All @@ -28,6 +30,7 @@ const PREPARE_EPOCH_LIMIT = 1;
*
*/
export class PrepareNextSlotScheduler {
private transitionConfig: TransitionConfigurationV1 | null = null;
constructor(
private readonly chain: IBeaconChain,
private readonly config: IChainForkConfig,
Expand All @@ -36,11 +39,24 @@ export class PrepareNextSlotScheduler {
private readonly signal: AbortSignal
) {
this.chain.emitter.on(ChainEvent.clockSlot, this.prepareForNextSlot);
// If the merge is configured
if (isFinite(this.config.BELLATRIX_FORK_EPOCH)) {
this.transitionConfig = {
terminalTotalDifficulty: numToQuantity(this.config.TERMINAL_TOTAL_DIFFICULTY),
terminalBlockHash: bytesToData(this.config.TERMINAL_BLOCK_HASH),
/** terminalBlockNumber has to be set to zero for now as per specs */
terminalBlockNumber: numToQuantity(0),
};
this.chain.emitter.on(ChainEvent.clockSlot, this.performExchangeTransitionHB);
}

this.signal.addEventListener(
"abort",
() => {
this.chain.emitter.off(ChainEvent.clockSlot, this.prepareForNextSlot);
if (this.transitionConfig) {
this.chain.emitter.off(ChainEvent.clockSlot, this.performExchangeTransitionHB);
}
},
{once: true}
);
Expand Down Expand Up @@ -138,4 +154,24 @@ export class PrepareNextSlotScheduler {
this.logger.error("Failed to run prepareForNextSlot", {nextEpoch, isEpochTransition, prepareSlot}, e as Error);
}
};

/**
* perform heart beat for EL lest it logs warning that CL is not connected
*/
performExchangeTransitionHB = async (_clockSlot: Slot): Promise<void> => {
const transitionConfig = this.transitionConfig;
if (transitionConfig) {
const elTransitionConfig = await this.chain.executionEngine.exchangeTransitionConfigurationV1(transitionConfig);
if (
elTransitionConfig.terminalTotalDifficulty !== transitionConfig.terminalTotalDifficulty ||
elTransitionConfig.terminalBlockHash !== transitionConfig.terminalBlockHash
) {
this.logger.error(
`Transition config mismatch, actual=${JSON.stringify(elTransitionConfig)}, expected=${JSON.stringify(
transitionConfig
)}`
);
}
}
};
}
3 changes: 3 additions & 0 deletions packages/beacon-node/src/execution/engine/disabled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ export class ExecutionEngineDisabled implements IExecutionEngine {
async getPayload(): Promise<never> {
throw Error("Execution engine disabled");
}
async exchangeTransitionConfigurationV1(): Promise<never> {
throw Error("Execution engine disabled");
}
}
33 changes: 33 additions & 0 deletions packages/beacon-node/src/execution/engine/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
PayloadId,
PayloadAttributes,
ApiPayloadAttributes,
TransitionConfigurationV1,
} from "./interface.js";
import {PayloadIdCache} from "./payloadIdCache.js";

Expand Down Expand Up @@ -60,6 +61,7 @@ export const defaultExecutionEngineHttpOpts: ExecutionEngineHttpOpts = {
const notifyNewPayloadOpts: ReqOpts = {routeId: "notifyNewPayload"};
const forkchoiceUpdatedV1Opts: ReqOpts = {routeId: "forkchoiceUpdated"};
const getPayloadOpts: ReqOpts = {routeId: "getPayload"};
const exchageTransitionConfigOpts: ReqOpts = {routeId: "exchangeTransitionConfiguration"};

/**
* based on Ethereum JSON-RPC API and inherits the following properties of this standard:
Expand Down Expand Up @@ -283,6 +285,29 @@ export class ExecutionEngineHttp implements IExecutionEngine {
return parseExecutionPayload(executionPayloadRpc);
}

/**
* `engine_exchangeTransitionConfigurationV1`
*
* An api method for EL<>CL transition config matching and heartbeat
*/

async exchangeTransitionConfigurationV1(
transitionConfiguration: TransitionConfigurationV1
): Promise<TransitionConfigurationV1> {
const method = "engine_exchangeTransitionConfigurationV1";
const exchangeTransitionConfigurationV1Res = await this.rpc.fetchWithRetries<
EngineApiRpcReturnTypes[typeof method],
EngineApiRpcParamTypes[typeof method]
>(
{
method,
params: [transitionConfiguration],
},
exchageTransitionConfigOpts
);
return exchangeTransitionConfigurationV1Res;
}

async prunePayloadIdCache(): Promise<void> {
this.payloadIdCache.prune();
}
Expand All @@ -308,6 +333,10 @@ type EngineApiRpcParamTypes = {
* 1. payloadId: QUANTITY, 64 Bits - Identifier of the payload building process
*/
engine_getPayloadV1: [QUANTITY];
/**
* 1. Object - Instance of TransitionConfigurationV1
*/
engine_exchangeTransitionConfigurationV1: [TransitionConfigurationV1];
};

type EngineApiRpcReturnTypes = {
Expand All @@ -328,6 +357,10 @@ type EngineApiRpcReturnTypes = {
* payloadId | Error: QUANTITY, 64 Bits - Identifier of the payload building process
*/
engine_getPayloadV1: ExecutionPayloadRpc;
/**
* Object - Instance of TransitionConfigurationV1
*/
engine_exchangeTransitionConfigurationV1: TransitionConfigurationV1;
};

type ExecutionPayloadRpc = {
Expand Down
11 changes: 11 additions & 0 deletions packages/beacon-node/src/execution/engine/interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {bellatrix, RootHex} from "@lodestar/types";
import {DATA, QUANTITY} from "../../eth1/provider/utils.js";
import {PayloadIdCache, PayloadId, ApiPayloadAttributes} from "./payloadIdCache.js";

export {PayloadIdCache, PayloadId, ApiPayloadAttributes};
Expand Down Expand Up @@ -47,6 +48,12 @@ export type PayloadAttributes = {
suggestedFeeRecipient: string;
};

export type TransitionConfigurationV1 = {
terminalTotalDifficulty: QUANTITY;
terminalBlockHash: DATA;
terminalBlockNumber: QUANTITY;
};

/**
* Execution engine represents an abstract protocol to interact with execution clients. Potential transports include:
* - JSON RPC over network
Expand Down Expand Up @@ -93,4 +100,8 @@ export interface IExecutionEngine {
* https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/validator.md#get_payload
*/
getPayload(payloadId: PayloadId): Promise<bellatrix.ExecutionPayload>;

exchangeTransitionConfigurationV1(
transitionConfiguration: TransitionConfigurationV1
): Promise<TransitionConfigurationV1>;
}
12 changes: 12 additions & 0 deletions packages/beacon-node/src/execution/engine/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
PayloadId,
PayloadAttributes,
PayloadIdCache,
TransitionConfigurationV1,
} from "./interface.js";
const INTEROP_GAS_LIMIT = 30e6;

Expand Down Expand Up @@ -228,6 +229,17 @@ export class ExecutionEngineMock implements IExecutionEngine {
return payload;
}

async exchangeTransitionConfigurationV1(
transitionConfiguration: TransitionConfigurationV1
): Promise<TransitionConfigurationV1> {
const resTransitionConfig = {
terminalTotalDifficulty: transitionConfiguration.terminalTotalDifficulty,
terminalBlockHash: transitionConfiguration.terminalBlockHash,
terminalBlockNumber: transitionConfiguration.terminalBlockNumber,
};
return resTransitionConfig;
}

/**
* Non-spec method just to add more known blocks to this mock.
*/
Expand Down

0 comments on commit 1778fc4

Please sign in to comment.