# 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)