# EPF6 - Week 17
## Overview
- Attended Lodestar Weekly Standups and [shared updates](https://github.com/ChainSafe/lodestar/wiki/Lodestar-Weekly-Standups-2025#epf-contributors-progress)
- Finalized the first draft of the NodePair recreation, making the simulation framework fully based on Kurtosis SDK functions
- Clarified the role of JWT authentication and verified that the **SHARED_JWT_SECRET** is not required for assertions
- Successfully ran **multifork test** through Altair fork (epoch 3), confirming stable behavior in the early simulation stages
- Encountered and investigated multiple runtime issues, including Lighthouse peer connection errors and insufficient account funding on the execution layer
- Started drafting the presentation bulletpoints for **EPF Day** at Devconnect Buenos Aires
## Main points
### JWT Authentication Clarification
- Confirmed the **SHARED_JWT_SECRET** is not required for assertion operations.
**Details**:
- Discussed with mentor before removing `jwtSecretHex` from configuration.
- Lodestar and ethereum-package use different hardcoded JWTs, but this does **not** impact assertions.
- JWT is only used for EL↔CL communication, which Kurtosis manages internally.
### NodePair Recreation & Architecture
- **Migration Achievement**: The simulation framework is now fully based on Kurtosis SDK functions and the ethereum-package, managing CL, EL, and VC services natively.
- Draft implementation introduces **health gates** to ensure network readiness:
```typescript
await this.waitForBeaconGenesis()
```
The new `waitForBeaconGenesis()` polls each beacon node’s `/genesis` and `/health` endpoints until they return success codes (**200** or **206**).
It substitutes **[initGenesisState()](https://github.com/ChainSafe/lodestar/blob/eb034b5727e61d764e804ffc0c9eb1666f90bd76/packages/cli/test/utils/crucible/simulation.ts#L317)**.
:::success
**Why?**
These function aims to reproduce the Docker-based behavior of waiting for genesis creation and client readiness.
The **ethereum-package** autonomously computes and mounts the genesis state. With Kurtosis, **readiness** is derived by clients observation.
:::
Health check implementation:
```typescript!
private async waitForBeaconGenesis({timeoutMs}: {timeoutMs: number}) {
const deadline = Date.now() + timeoutMs;
const poll = async (fn: () => Promise<boolean>, label: string, everyMs = 1000) => {
while (true) {
try {
if (await fn()) return;
} catch {}
if (Date.now() > deadline) throw new Error(`Timeout waiting for ${label}`);
await new Promise((r) => setTimeout(r, everyMs));
}
};
// All beacons respond to /genesis
await Promise.all(
this.nodes.map((n) =>
poll(async () => {
const res = await n.beacon.api.beacon.getGenesis(); // Wait for genesis endpoint to respond
return !!res.value()?.genesisTime;
}, `${n.id} /genesis`)
)
);
// Health is SYNCING or READY
await Promise.all(
this.nodes.map((n) =>
poll(async () => {
const {status} = await n.beacon.api.node.getHealth();
return status === 200 || status === 206;
}, `${n.id} health`)
)
);
}
```
- Defines a `poll()` helper: A reusable polling utility that repeatedly checks a condition until it succeeds or times out.
- Waits on all nodes in parallel using `Promise.all`.
### Lighthouse node handling
- Encountered a `connectPeer failed with status 500: Can not dial self error`.
**Root cause**:
Identified that Lighthouse nodes were being processed through Lodestar’s peer connection logic, which is incompatible.
**Fixed applied**:
Patched [`utils/network.ts`](https://github.com/ChainSafe/lodestar/blob/feature/kurtosis-sim-tests/packages/cli/test/utils/crucible/utils/network.ts) to skip peer connection attempts for Lighthouse nodes, preventing incompatible connectPeer calls and ensuring stable multi-client runs:
```typescript!
if (node.client !== BeaconClient.Lodestar) continue;
```
### Prefunded account issue
- The simulation failed at epoch 3 due to:
```markdown
TransactionRevertInstructionError: insufficient funds for gas * price + value
```
**Root cause**:
the [EL_GENESIS_ACCOUNT](https://) used in `createAccountBalanceAssertion()` was not recognized by the execution client
**Fixed applied**:
Tested `prefunded_accounts` field in `multiFork.yml`:
```yaml!
prefunded_accounts: '{"0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B": {"balance": "100ETH"}}'
```
This aligns the execution client (Geth) balance state with the account expected by the assertion logic.
### Simulation behavior
- The simulation runs smoothly up to Altair epoch 3.
> [!WARNING] Current status
The main **blocker** now is ==transaction signing==, as the execution client **does not yet** link the prefunded account for the assertion transactions.
## Learnings & Outcomes
| Area | Insight |
|------|---------|
| **Architecture** | Health gate approach (`waitForBeaconGenesis`) successfully replaces Docker's implicit readiness behavior |
| **Multi-Client Support** | Handling **multiple CL clients** (Lodestar + Lighthouse) revealed differing connection patterns, valuable for future multi-client simulations |
| **Genesis Configuration** | `prefunded_accounts` parameter demonstrates extensibility of **ethereum-package** for assertion-level funding |
## Week 18 TODOs
- Continue testing and refining **prefunded account** integration for execution-layer transaction signing.
- Verify that assertions using **EL_GENESIS_ACCOUNT** pass through all fork epochs.
- Commit the updated **NodePair[]** recreation for mentor review and feedback.
- Iterate on Devconnect presentation:
- Focus on architecture overview
- Document migration flow
- Highlight key learnings and challenges
### Useful resources checked
Ethereum docs for [eth_accounts](https://www.quicknode.com/docs/ethereum/eth_accounts)