This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Teku is an open-source Ethereum consensus client written in Java, implementing a full beacon node and validator client. It is written in Java 21+ and follows the Ethereum consensus specifications.
# Full build with tests
./gradlew build
# Build without tests
./gradlew assemble
# Create distribution packages
./gradlew distTar installDist
# Build Docker image
./gradlew distDocker# Apply Google Java code formatting (required before committing)
./gradlew spotlessApply
# Check code formatting
./gradlew spotlessCheck# Run all unit tests
./gradlew test
# Run tests for a specific module (example)
./gradlew :ethereum:spec:test
# Run integration tests
./gradlew integrationTest
# Run reference tests (consensus spec tests)
./gradlew referenceTest
# Run acceptance tests
./gradlew acceptanceTest
# Run property tests
./gradlew propertyTestThe built distribution is located in:
- Packaged:
build/distributions/ - Expanded (ready to run):
build/install/teku/
graph TB
subgraph "Application Layer"
CLI[Teku CLI / BeaconNodeCommand]
CLI --> Node[Node<br/>COMBINED/VC_ONLY/BOOTNODE]
end
subgraph "Service Layer"
Node --> SC[ServiceController]
SC --> SS[StorageService]
SC --> ELS[ExecutionLayerService]
SC --> BCS[BeaconChainService]
SC --> PCS[PowchainService]
SC --> VCS[ValidatorClientService]
SC --> TS[TimerService]
end
subgraph "Core Logic Layer"
BCS --> Spec[ethereum/spec<br/>Consensus Rules]
BCS --> ST[ethereum/statetransition<br/>State Processing]
BCS --> Sync[beacon/sync<br/>Block Sync]
VCS --> ValClient[validator/client<br/>Duties & Slashing Protection]
ELS --> ELM[ExecutionLayerManager<br/>Engine API / Builder API]
end
subgraph "Data & Storage Layer"
SS --> DB[(Database<br/>RocksDB/LevelDB)]
SS --> PA[storage/protoarray<br/>Fork Choice]
BCS --> Storage[storage/api<br/>ChainStorage]
Storage --> DB
end
subgraph "Networking Layer"
BCS --> Net[networking/p2p<br/>Libp2p Gossip]
Net --> Peers[Peer Network]
end
subgraph "API Layer"
BCS --> RestAPI[data/beaconrestapi<br/>Beacon API]
VCS --> ValAPI[validator/api<br/>Validator API]
end
subgraph "External Integration"
ELM --> EL[Execution Layer Client<br/>Geth/Nethermind/Besu]
ELM --> Builder[MEV-Boost Builder]
PCS --> ETH1[Ethereum PoW Chain<br/>Deposit Contract]
end
subgraph "Event Channels (Event-Driven Communication)"
TS -.SlotEventsChannel.-> BCS
BCS -.VoteUpdateChannel.-> PA
BCS -.CombinedStorageChannel.-> Storage
ELS -.ExecutionClientEventsChannel.-> BCS
PCS -.Eth1EventsChannel.-> BCS
end
subgraph "Infrastructure Layer"
Infra[infrastructure/<br/>async, events, metrics, crypto, BLS, KZG, SSZ]
Spec --> Infra
ST --> Infra
Storage --> Infra
Net --> Infra
end
style CLI fill:#e1f5ff
style Node fill:#e1f5ff
style BCS fill:#ffe1e1
style ELS fill:#ffe1e1
style VCS fill:#ffe1e1
style Spec fill:#fff4e1
style DB fill:#e1ffe1
style Net fill:#f0e1ff
style RestAPI fill:#ffe1f5
style EL fill:#f5f5f5
style Infra fill:#e8e8e8
┌─────────────────────────────────────────────────────────────┐
│ teku/ (Application Entry Point) │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────┴────────────────────────────────┐
│ services/ (Service Orchestration Layer) │
│ ├─ beaconchain, chainstorage, executionlayer │
│ ├─ powchain, timer, bootnode, zkchain │
└────────────┬──────────────────────────┬─────────────────────┘
│ │
┌────────────┴──────────┐ ┌───────────┴──────────────────────┐
│ validator/ │ │ beacon/ │
│ ├─ client │ │ ├─ pow, sync, validator │
│ ├─ api │ │ │
│ └─ beaconnode │ └───────────────────────────────────┘
└───────────┬───────────┘
│
┌───────────┴─────────────────────────────────────────────────┐
│ ethereum/ (Core Consensus Layer) │
│ ├─ spec (Consensus specification) │
│ ├─ statetransition (Block/slot processing) │
│ ├─ executionlayer (EL integration) │
│ ├─ dataproviders (Data queries) │
│ ├─ networks (Network configs) │
│ └─ weaksubjectivity (Checkpoint validation) │
└─────────┬──────────────────────────┬────────────────────────┘
│ │
┌─────────┴──────────┐ ┌───────────┴──────────────────┐
│ storage/ │ │ networking/ │
│ ├─ api │ │ ├─ p2p (Libp2p) │
│ ├─ protoarray │ │ ├─ eth2 (Protocol) │
│ └─ archive │ │ └─ nat │
└─────────┬──────────┘ └──────────┬───────────────────┘
│ │
┌─────────┴────────────────────────┴───────────────────────────┐
│ data/ (REST API & Serialization) │
│ ├─ beaconrestapi (Beacon Chain REST API) │
│ ├─ provider (Data providers) │
│ ├─ serializer (SSZ/JSON serialization) │
│ └─ publisher (Metrics publishing) │
└──────────────────────────┬───────────────────────────────────┘
│
┌──────────────────────────┴───────────────────────────────────┐
│ infrastructure/ (Foundation Layer) │
│ ├─ async, events, metrics, logging │
│ ├─ bls, kzg, crypto │
│ ├─ ssz (serialization) │
│ ├─ bytes, collections, unsigned │
│ └─ http, restapi, serviceutils, time, yaml │
└──────────────────────────────────────────────────────────────┘
Teku supports three operational modes controlled by NodeMode:
- COMBINED: Full beacon node + validator client (default)
- VC_ONLY: Validator client only (connects to remote beacon node)
- BOOTNODE_ONLY: Network bootstrap node only
Entry point: teku/src/main/java/tech/pegasys/teku/Teku.java
CLI parsing: teku/src/main/java/tech/pegasys/teku/cli/BeaconNodeCommand.java
Teku uses a composable service architecture where all major components are Service implementations managed by ServiceController. Services start in dependency order and stop in reverse order:
ServiceController
├─ StorageService (database and state storage)
├─ ExecutionLayerService (Execution Layer integration)
├─ BeaconChainService (consensus layer processing)
├─ PowchainService (PoW chain monitoring for deposits)
├─ ValidatorClientService (validator duties)
└─ TimerService (slot timing)
ethereum/spec - Core consensus specification implementation
- Organized by milestones: PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, FULU, GLOAS
Spec.javaprovides unified API across all forksSpecVersion.javaencapsulates version-specific operationsForkSchedule.javadetermines which fork rules apply at each epoch
beacon/ - Beacon chain functionality
beacon:pow- Proof-of-Work chain interactionbeacon:sync- Block synchronization logicbeacon:validator- Validator-specific beacon operations
ethereum/statetransition - State transition logic
- Processes blocks, slots, attestations according to consensus rules
- Validates and applies state changes
ethereum/executionlayer - Execution Layer integration
ExecutionLayerManagerorchestrates EL interactionsExecutionEngineClientimplements Engine API (newPayload, forkchoiceUpdated)BuilderClientintegrates with MEV-Boost builders- Supports Web3j and REST transport layers
storage/ - Database and state management
- Multiple storage modes: ARCHIVE, PRUNE_ANCIENT_STATES, PRUNE_HOT_STATES
- Supports RocksDB and LevelDB backends
storage:protoarrayimplements fork choice algorithmstorage:archivehandles historical data (blobs, etc.)
data/beaconrestapi - REST API implementation
- Implements standard Beacon Chain API endpoints
- Separate validator API endpoints
networking/ - Peer-to-peer networking
networking:p2p- Libp2p integration for gossip and discoverynetworking:eth2- Ethereum 2.0 protocol-specific networking- Handles peer management, attestation/block propagation
validator/ - Validator client
validator:client- Validator duties, slashing protectionvalidator:api- REST API for external validator clientsvalidator:beaconnode- Beacon node client interface
infrastructure/ - Shared utilities
- async, events, metrics, logging, crypto, BLS, KZG
- SSZ serialization (
infrastructure:ssz) - Event channels for inter-service communication
The system uses an event-driven architecture via EventChannels:
- SlotEventsChannel - Fires every slot (12 seconds), drives consensus processing
- VoteUpdateChannel - Fork choice updates
- CombinedStorageChannel - Storage state updates
- ExecutionClientEventsChannel - Execution Layer events
- Eth1EventsChannel - PoW chain events (deposits)
Services subscribe to relevant channels and react asynchronously using SafeFuture for non-blocking operations.
- SlotEventsChannel.onSlot() fires every 12 seconds
- BeaconChainService processes the slot:
- Performs per-slot state transition
- Processes pending attestations
- Triggers block proposal if validator's duty
- ExecutionLayerManager queried for execution payload (if proposing)
- Fork choice updated via VoteUpdateChannel → BatchingVoteUpdateChannel
- Network layer gossips blocks/attestations to peers
- Storage persists finalized states and blocks
The codebase supports multiple Ethereum consensus forks. Each milestone has:
- Fork-specific
SpecConfig(e.g.,AltairSpecConfig,CapellaSpecConfig) - Milestone-specific data structures (BeaconState, BeaconBlock variants)
- State transition logic adapted for the fork
ForkSchedule determines which milestone is active at each epoch, and Spec provides version-appropriate implementations.
Teku integrates with Execution Layer clients (Geth, Nethermind, Besu, etc.) via:
- Engine API: newPayload, forkchoiceUpdated, getPayload
- Builder API: MEV-Boost integration for block building
- Web3 API: eth_* methods for legacy PoW monitoring
The ExecutionLayerManager abstracts these interactions and handles fallback/retry logic.
- Unit tests: Test individual components in isolation (run with
./gradlew test) - Integration tests: Test component interactions (run with
./gradlew integrationTest) - Reference tests: Official Ethereum consensus spec tests (run with
./gradlew referenceTest) - Acceptance tests: End-to-end scenarios with real network simulation (run with
./gradlew acceptanceTest) - Property tests: Randomized property-based tests (run with
./gradlew propertyTest)
Each module has its own test suite under src/test/java and test fixtures under src/testFixtures/java.
- Coding style: Google Java conventions (enforced by Spotless)
- Imports: Always use proper import statements instead of fully qualified class names in code
- Good:
import tech.pegasys.teku.spec.logic.common.util.DataColumnSidecarValidationHelper; ... DataColumnSidecarValidationHelper helper = ... - Bad:
tech.pegasys.teku.spec.logic.common.util.DataColumnSidecarValidationHelper helper = ...
- Good:
- Async operations: Use
SafeFutureandAsyncRunnerinstead of raw CompletableFuture - Immutability: Prefer immutable data structures (record types, SszData implementations)
- Error handling: Use checked exceptions for recoverable errors, unchecked for programming errors
- Testing: All code must have automated test coverage (no manual tests)
- Commit messages: Imperative mood, present tense ("Add feature" not "Added feature")
See Hyperledger Besu Coding Conventions for additional guidelines.
When implementing features that vary across Ethereum consensus forks:
-
Add convenience methods to
Spec.javafor fork-specific helpers to avoid repetitiveOptional.orElseThrow()boilerplate. See:getExecutionRequestsProcessor(),getDataColumnSidecarUtil() -
Use abstract test base classes for components with significantly different behavior across forks, instead of
@TestSpecContext. Each fork gets its own test class that extends the abstract base and implementscreateSpec(). See:AbstractDataColumnSidecarGossipValidatorTest,AbstractAttestationValidatorTest -
Pass
SpecLogicto validation helpers instead of fork-specific implementations. Let each helper extract what it needs internally (e.g., casting toMiscHelpersFulu). This keeps generic validators fork-agnostic. See:DataColumnSidecarUtilhierarchy -
Create validation utility hierarchies for fork-specific validation logic:
- Abstract base class:
ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/common/util/ - Fork implementations:
ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/{fork}/util/ - Integrate via SpecLogic: Add getter method to SpecLogic interface and implement in fork-specific SpecLogic classes
- Add convenience method to Spec.java that handles the Optional unwrapping
- Abstract test base:
ethereum/statetransition/src/test/.../Abstract{Feature}Test.java
Example pattern (DataColumnSidecarUtil):
- Base:
DataColumnSidecarUtil(abstract class with common methods) - Fulu:
DataColumnSidecarUtilFulu(includes header validation, inclusion proofs) - Gloas:
DataColumnSidecarUtilGloas(simplified, no headers, validates execution payload bids) - Integration:
SpecLogic.getDataColumnSidecarUtil()→Spec.getDataColumnSidecarUtil(slot)
- Abstract base class:
settings.gradle- Defines all 75+ submodulesbuild.gradle- Root build configuration, dependency managementCONTRIBUTING.md- Contribution guidelines and CLA processethereum/spec/src/main/java/tech/pegasys/teku/spec/Spec.java- Main consensus spec APIteku/src/main/java/tech/pegasys/teku/Teku.java- Application entry pointservices/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainService.java- Core beacon chain service
The codebase enforces layered dependencies:
- infrastructure/ - Lowest level, no dependencies on other Teku modules
- ethereum/spec - Depends only on infrastructure
- ethereum/* - Can depend on infrastructure and other ethereum modules
- services/ - Composes ethereum, storage, networking modules
- teku/ - Top-level orchestration, depends on services
Circular dependencies are prevented by build-time dependency checks (DepCheckPlugin).
- Make changes to relevant module(s)
- Run
./gradlew spotlessApplyto format code - Run
./gradlew testto run unit tests - Run module-specific tests:
./gradlew :<module>:test - Run
./gradlew buildfor full verification before committing
After building with ./gradlew installDist, run:
./build/install/teku/bin/teku --help