Skip to content

Commit a3226be

Browse files
committed
Add Nix dev shell with pinned test binaries
Introduce a reproducible development environment so the project builds and tests the same way on any machine. The flake provides the pinned Rust toolchain, nightly rustfmt, and the bitcoind/electrs binaries the integration tests need; .envrc loads it via direnv and the justfile wraps the common check/fmt/test commands to mirror CI's gates. bitcoind is pinned to 27.1 from an older nixpkgs rev because the tests' bundled corepc-node only decodes the 27.x getblockchaininfo RPC schema; the current 25.11 channel ships 30.0 and fails decoding. For electrs we package the exact prebuilt esplora binary CI downloads and patch it for NixOS rather than using nixpkgs' blockstream-electrs. The nixpkgs build is much newer and its initial regtest indexing takes around 80 seconds, which overruns the tests' chain sync timeout and makes every integration test fail locally. Building that old revision from source under the current toolchain is fragile, so reusing the same binary CI runs is the cheapest way to match its behaviour. The prebuilt only exists for x86_64 linux and macOS, the two platforms the download script supports.
1 parent f13fcea commit a3226be

4 files changed

Lines changed: 287 additions & 0 deletions

File tree

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

flake.lock

Lines changed: 113 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
{
2+
description = "LDK Node Development Environment";
3+
4+
inputs = {
5+
# Nixpkgs channel. New channels are released every 6 months.
6+
# See: https://github.com/NixOS/nixpkgs/tags
7+
nixpkgs.url = "github:nixos/nixpkgs/25.11";
8+
9+
# This makes it easy for the flake to be multi-platform.
10+
# See: https://github.com/numtide/flake-utils
11+
flake-utils.url = "github:numtide/flake-utils";
12+
13+
# Provides Rust toolchains.
14+
# See: https://github.com/oxalica/rust-overlay
15+
rust-overlay.url = "github:oxalica/rust-overlay";
16+
17+
# Pinned nixpkgs that ships bitcoind 27.1. The integration tests' bundled
18+
# `corepc-node` deserializes the 27.x `getblockchaininfo` schema, so newer
19+
# bitcoind (25.11 ships 30.0) fails RPC decoding. Used only for BITCOIND_EXE.
20+
nixpkgs-bitcoind.url = "github:nixos/nixpkgs/ab7b6889ae9d484eed2876868209e33eb262511d";
21+
};
22+
23+
outputs =
24+
{
25+
self,
26+
nixpkgs,
27+
flake-utils,
28+
rust-overlay,
29+
nixpkgs-bitcoind,
30+
}:
31+
flake-utils.lib.eachDefaultSystem (
32+
system:
33+
let
34+
# Overlays provide additional packages not available in the channels.
35+
overlays = [
36+
# Provides the rust-bin package; a set of pre-built Rust toolchains.
37+
(import rust-overlay)
38+
];
39+
40+
# The final set of packages.
41+
pkgs = import nixpkgs {
42+
# Inheriting from system is what makes this multi-platform.
43+
# We also inherit the overlays that we want to use.
44+
inherit system overlays;
45+
};
46+
47+
# bitcoind 27.1 from the pinned input (see inputs above).
48+
bitcoind = nixpkgs-bitcoind.legacyPackages.${system}.bitcoind;
49+
50+
# The specific Rust toolchain that we use in development shells.
51+
# Matches the `rust-version` declared in Cargo.toml. We use the `minimal`
52+
# profile (rustc, cargo, rust-std) plus clippy and rust-src, but
53+
# deliberately exclude `rustfmt`: this repo's `rustfmt.toml` relies on
54+
# nightly-only options, so formatting is supplied by `rustfmt-nightly`
55+
# below to keep `just fmt`/`just check` consistent with CI's nightly job.
56+
rust-toolchain = pkgs.rust-bin.stable."1.85.1".minimal.override {
57+
extensions = [
58+
"rust-src" # Needed for the rust-analyzer extension to work.
59+
"clippy" # Linter used by `just check`.
60+
];
61+
};
62+
63+
# Nightly rustfmt only. `cargo fmt` shells out to whichever `rustfmt` is
64+
# on PATH, so a nightly rustfmt lets the nightly-only options in
65+
# `rustfmt.toml` apply even though cargo/rustc are pinned to stable.
66+
rustfmt-nightly = pkgs.rust-bin.nightly.latest.rustfmt;
67+
68+
# Esplora/HTTP electrs for the integration tests' Esplora chain source.
69+
#
70+
# We deliberately do NOT use nixpkgs' `blockstream-electrs`: it is a far
71+
# newer build whose initial regtest indexing takes ~80s, blowing past the
72+
# tests' sync timeout. Instead we pin the *exact* prebuilt binary CI uses
73+
# (see scripts/download_bitcoind_electrs.sh) and patch it to run on Nix.
74+
# This keeps local test behaviour identical to CI.
75+
electrs-esplora =
76+
let
77+
rev = "a33e97e1a1fc63fa9c20a116bb92579bbf43b254";
78+
sources = {
79+
x86_64-linux = {
80+
file = "electrs_linux_esplora_${rev}.zip";
81+
sha256 = "865e26a96e8df77df01d96f2f569dcf9622fc87a8d99a9b8fe30861a4db9ddf1";
82+
};
83+
x86_64-darwin = {
84+
file = "electrs_macos_esplora_${rev}.zip";
85+
sha256 = "2d5ff149e8a2482d3658e9b386830dfc40c8fbd7c175ca7cbac58240a9505bcd";
86+
};
87+
};
88+
src =
89+
sources.${system}
90+
or (throw "no prebuilt esplora electrs for ${system}");
91+
in
92+
pkgs.stdenv.mkDerivation {
93+
pname = "electrs-esplora";
94+
version = "esplora-${builtins.substring 0 9 rev}";
95+
src = pkgs.fetchurl {
96+
url = "https://github.com/RCasatta/electrsd/releases/download/electrs_releases/${src.file}";
97+
inherit (src) sha256;
98+
};
99+
nativeBuildInputs =
100+
[ pkgs.unzip ] ++ pkgs.lib.optional pkgs.stdenv.isLinux pkgs.autoPatchelfHook;
101+
buildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.stdenv.cc.cc.lib ];
102+
unpackPhase = ''
103+
runHook preUnpack
104+
unzip "$src"
105+
runHook postUnpack
106+
'';
107+
installPhase = ''
108+
runHook preInstall
109+
install -Dm755 electrs "$out/bin/electrs"
110+
runHook postInstall
111+
'';
112+
};
113+
114+
in
115+
{
116+
# The development shell. Use `nix develop` or direnv to enter it.
117+
devShells.default = pkgs.mkShell {
118+
name = "ldk-node-dev-shell";
119+
120+
packages = with pkgs; [
121+
rustfmt-nightly # Nightly rustfmt; must precede the stable toolchain on PATH.
122+
rust-toolchain # Rust toolchain (no rustfmt; see above).
123+
nodejs # JavaScript runtime, required for MCP tools
124+
mold # Fast linker for Rust/C/C++
125+
pnpm # Package manager for JavaScript, required for MCP tools
126+
pkg-config # Required by build scripts that link against system libraries
127+
just # Command runner used for `just check`, `just fmt`, etc.
128+
stdenv.cc.cc.lib # C++ standard library for runtime
129+
];
130+
131+
env = {
132+
# OpenSSL configuration for Nix
133+
PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig";
134+
# C++ standard library path for runtime
135+
LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib";
136+
# Integration tests (run with `--cfg no_download`) locate these via env
137+
# rather than downloading generic-linux binaries that can't run on NixOS.
138+
BITCOIND_EXE = "${bitcoind}/bin/bitcoind";
139+
ELECTRS_EXE = "${electrs-esplora}/bin/electrs";
140+
};
141+
142+
shellHook = ''
143+
echo "LDK Node dev shell"
144+
rustc --version
145+
cargo --version
146+
'';
147+
};
148+
}
149+
);
150+
}

justfile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
default:
2+
@just --list --unsorted
3+
4+
# Validate: rustfmt check + clippy with warnings denied (matches CI's deny-warnings gate).
5+
check:
6+
cargo fmt --all -- --check
7+
cargo clippy --all-targets -- -D warnings
8+
9+
# Format all sources in place.
10+
fmt:
11+
cargo fmt --all
12+
13+
# Apply clippy autofixes across all targets.
14+
fix:
15+
cargo clippy --all-targets --fix --allow-dirty --allow-staged
16+
17+
# Run library unit tests only. No bitcoind/electrs required.
18+
test:
19+
RUSTFLAGS="-D warnings" cargo test --lib
20+
21+
# Run full suite incl. integration tests. Needs bitcoind+electrs on PATH (CI's --cfg no_download).
22+
test-all:
23+
RUSTFLAGS="--cfg no_download -D warnings" cargo test

0 commit comments

Comments
 (0)