Lean consensus client in C#, built with .NET 10+, Rust FFI for hash-based crypto (leanSig/leanMultisig), and Nethermind dotnet-libp2p for networking.
- .NET SDK 10.0+ (see
global.json) - Rust toolchain (
cargo) for native crypto FFI - libmsquic (version 2+) for QUIC transport
- Docker (for integration tests and interop)
- Git submodules:
git submodule update --init --recursive
macOS (Homebrew):
brew install microsoft/msquic/libmsquicAfter installing, copy the library next to the published binary so .NET can find it (macOS SIP strips DYLD_LIBRARY_PATH):
cp /opt/homebrew/lib/libmsquic.dylib <publish-dir>/Ubuntu / Debian:
wget https://packages.microsoft.com/config/ubuntu/24.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb
sudo apt-get update && sudo apt-get install -y libmsquic# Clone with submodules
git clone --recursive https://github.com/nleanEth/nlean.git
cd nlean
# Build native crypto bindings (requires Rust toolchain)
./scripts/build-native.sh
# Build patched libp2p packages (required for gossip/quic compatibility)
./scripts/libp2p/build-patched-pubsub-package.sh
./scripts/libp2p/build-patched-quic-package.sh
# Build
dotnet build Lean.sln -c Release
# Run all unit tests
dotnet test Lean.sln -c ReleaseThere are three ways to run nlean: Docker, release binary, or build from source. Choose one below.
Everything is self-contained — no need to install libmsquic or .NET separately.
# Pull pre-built image
docker pull ghcr.io/nleaneth/nlean:latest
# Or build locally
docker build -t nlean --build-arg GIT_SHA=$(git rev-parse --short HEAD) .
# Run
docker run ghcr.io/nleaneth/nlean:latest \
--validator-config /path/to/validator-config.yaml \
--node nlean_0 \
--data-dir /data/nlean_0 \
--network devnet0 \
--node-key /path/to/nlean_0.key \
--socket-port 9101 \
--api-port 5052 \
--metrics-port 18081 \
--hash-sig-key-dir /path/to/hash-sig-keys \
--is-aggregator \
--log InformationDownload a release archive from GitHub Releases.
Linux (single-file or portable):
# Download and extract (example: linux-x64 single-file)
tar -xzf nlean-linux-x64.tar.gz
# Install libmsquic (required)
wget -q https://packages.microsoft.com/config/ubuntu/24.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb
sudo apt-get update && sudo apt-get install -y libmsquic
# Run (single-file binary — libmsquic is loaded from system path)
./lean-client-linux-x64/Lean.Client --helpmacOS arm64 (multi-file only):
# Download and extract
tar -xzf nlean-osx-arm64.tar.gz
# Install libmsquic via Homebrew
brew install microsoft/msquic/libmsquic
# Copy libmsquic next to the binary (required — macOS SIP strips DYLD_LIBRARY_PATH)
cp /opt/homebrew/lib/libmsquic.dylib lean-client-osx-arm64-portable/
# Run
./lean-client-osx-arm64-portable/Lean.Client --helpLinux — framework-dependent (requires .NET 10 runtime installed):
# Publish
dotnet publish src/Lean.Client/Lean.Client.csproj -c Release -o artifacts/lean-client --self-contained false
# Install libmsquic (required)
wget -q https://packages.microsoft.com/config/ubuntu/24.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb
sudo apt-get update && sudo apt-get install -y libmsquic
# Run
./artifacts/lean-client/Lean.Client --helpLinux — self-contained single-file:
dotnet publish src/Lean.Client/Lean.Client.csproj \
-c Release -r linux-x64 --self-contained true \
-p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true \
-o artifacts/lean-client
# Install libmsquic (required)
sudo apt-get install -y libmsquic
# Run
./artifacts/lean-client/Lean.Client --helpmacOS arm64 — self-contained multi-file:
# Install libmsquic (required before publish so it gets copied automatically)
brew install microsoft/msquic/libmsquic
mkdir -p src/Lean.Client/runtimes/osx-arm64/native
cp /opt/homebrew/lib/libmsquic.dylib src/Lean.Client/runtimes/osx-arm64/native/
dotnet publish src/Lean.Client/Lean.Client.csproj \
-c Release -r osx-arm64 --self-contained true \
-o artifacts/lean-client
# Run (libmsquic.dylib and liblean_crypto_ffi.dylib are copied automatically)
./artifacts/lean-client/Lean.Client --help./artifacts/lean-client/Lean.Client \
--validator-config /path/to/validator-config.yaml \
--node nlean_0 \
--data-dir data/nlean_0 \
--network devnet0 \
--node-key /path/to/nlean_0.key \
--socket-port 9101 \
--api-port 5052 \
--metrics-port 18081 \
--hash-sig-key-dir /path/to/hash-sig-keys \
--is-aggregator \
--log Informationsrc/
Lean.Client/ CLI entry point
Lean.Consensus/ Consensus, fork choice, sync (backfill, head, checkpoint)
Lean.Crypto/ Rust FFI bindings for leanSig / leanMultisig
Lean.Metrics/ Prometheus metrics
Lean.Network/ libp2p networking (gossip, RPC, discovery)
Lean.Node/ Node app orchestration
Lean.Storage/ Persistent storage layer
Lean.Validator/ Validator duties (propose, attest, aggregate)
tests/
Lean.Consensus.Tests/ Fork choice, sync, state transition (~291 tests)
Lean.Crypto.Tests/ FFI round-trip (~5 tests)
Lean.Network.Tests/ Networking (~40 tests)
Lean.Validator.Tests/ Validator service (~28 tests)
Lean.Integration.Tests/ Multi-node devnet (~4 tests)
native/
lean-crypto-ffi/ Rust crate for crypto bindings
client-cmds/
nlean-cmd.sh lean-quickstart client-cmd contract
scripts/
build-native.sh Build Rust FFI
libp2p/ Patched pubsub/quic package builders
vendor/
lean-quickstart/ Git submodule — devnet orchestration
# Run all tests (unit + integration, works on both Linux and macOS)
dotnet publish src/Lean.Client/Lean.Client.csproj -c Release -o artifacts/lean-client --self-contained false && dotnet test Lean.sln -c Release
# Unit tests only (no publish needed)
dotnet test Lean.sln -c Release --filter "TestCategory!=Integration"
# Consensus simulation (CI-aligned)
dotnet test tests/Lean.Consensus.Tests/Lean.Consensus.Tests.csproj \
-c Release \
--filter "FullyQualifiedName~ConsensusMultiNodeFinalizationV2Tests" \
/m:1 /nodeReuse:false
# Integration tests only (requires published binary + libmsquic)
dotnet publish src/Lean.Client/Lean.Client.csproj -c Release -o artifacts/lean-client --self-contained false
# Linux: sudo apt-get install -y libmsquic
# macOS: brew install microsoft/msquic/libmsquic && cp /opt/homebrew/lib/libmsquic.dylib artifacts/lean-client/
dotnet test tests/Lean.Integration.Tests/Lean.Integration.Tests.csproj -c Release
# Format check
dotnet tool install --tool-path ./.dotnet-tools dotnet-format
./.dotnet-tools/dotnet-format Lean.sln --check --fix-whitespace --exclude vendorUses lean-quickstart via git submodule:
git submodule update --init --recursive vendor/lean-quickstart
cd vendor/lean-quickstart
NETWORK_DIR=local-devnet-nlean ./spin-node.sh --node allThe client-cmds/nlean-cmd.sh script follows lean-quickstart's client-cmd contract, passing CLI flags directly.
See Option 1: Docker above for running via Docker.
Pre-built multi-arch images are published to GitHub Container Registry on every tagged release:
docker pull ghcr.io/nleaneth/nlean:latestGitHub Actions (.github/workflows/ci.yml) on PR and push to main:
| Job | Description |
|---|---|
format-check |
dotnet-format whitespace check |
build-test (ubuntu/macos) |
Build + unit tests + publish |
consensus-simulation |
Multi-node finalization simulation |
integration-tests |
4-node devnet integration (45 min timeout) |
On tag v* push (.github/workflows/docker-publish.yml + .github/workflows/release.yml):
| Job | Description |
|---|---|
docker build-and-push |
Multi-arch Docker image → ghcr.io/nleaneth/nlean |
release build |
Self-contained binaries (linux-x64, linux-arm64, osx-arm64) |
release create-release |
GitHub Release with tar.gz artifacts |
Each tagged release publishes the following artifacts:
| Artifact | Platform | Format | Description |
|---|---|---|---|
nlean-linux-x64.tar.gz |
Linux x64 | Single file | Self-contained single executable with all native libs bundled |
nlean-linux-x64-portable.tar.gz |
Linux x64 | Multi-file | Self-contained publish with separate DLLs and native libs |
nlean-linux-arm64.tar.gz |
Linux arm64 | Single file | Self-contained single executable with all native libs bundled |
nlean-linux-arm64-portable.tar.gz |
Linux arm64 | Multi-file | Self-contained publish with separate DLLs and native libs |
nlean-osx-arm64.tar.gz |
macOS arm64 | Multi-file | Self-contained publish with separate DLLs and native libs |
Note: macOS releases are multi-file only due to intermittent
libmsquiccrashes with single-file publish. On macOS, you must copylibmsquic.dylibnext to the binary — see Option 2: Release Binary for details.
See LICENSE.