diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..3550a30f2 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..52fabf4e2 --- /dev/null +++ b/flake.lock @@ -0,0 +1,113 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1764521362, + "narHash": "sha256-M101xMtWdF1eSD0xhiR8nG8CXRlHmv6V+VoY65Smwf4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "871b9fd269ff6246794583ce4ee1031e1da71895", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-bitcoind": { + "locked": { + "lastModified": 1727390236, + "narHash": "sha256-X2LaWM0WwoxUfu7cQmKyVbkYn0xwdRvBA+vkLg/OgnI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ab7b6889ae9d484eed2876868209e33eb262511d", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ab7b6889ae9d484eed2876868209e33eb262511d", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "nixpkgs-bitcoind": "nixpkgs-bitcoind", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1777950921, + "narHash": "sha256-NpOgt8ISaHTDNJZjNUfwFfbieKfRXzab4WKM31gZCGA=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "366ea19e0e55b768f74b7a0b2a20f847e7ae828d", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..4d6435815 --- /dev/null +++ b/flake.nix @@ -0,0 +1,150 @@ +{ + description = "LDK Node Development Environment"; + + inputs = { + # Nixpkgs channel. New channels are released every 6 months. + # See: https://github.com/NixOS/nixpkgs/tags + nixpkgs.url = "github:nixos/nixpkgs/25.11"; + + # This makes it easy for the flake to be multi-platform. + # See: https://github.com/numtide/flake-utils + flake-utils.url = "github:numtide/flake-utils"; + + # Provides Rust toolchains. + # See: https://github.com/oxalica/rust-overlay + rust-overlay.url = "github:oxalica/rust-overlay"; + + # Pinned nixpkgs that ships bitcoind 27.1. The integration tests' bundled + # `corepc-node` deserializes the 27.x `getblockchaininfo` schema, so newer + # bitcoind (25.11 ships 30.0) fails RPC decoding. Used only for BITCOIND_EXE. + nixpkgs-bitcoind.url = "github:nixos/nixpkgs/ab7b6889ae9d484eed2876868209e33eb262511d"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + rust-overlay, + nixpkgs-bitcoind, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + # Overlays provide additional packages not available in the channels. + overlays = [ + # Provides the rust-bin package; a set of pre-built Rust toolchains. + (import rust-overlay) + ]; + + # The final set of packages. + pkgs = import nixpkgs { + # Inheriting from system is what makes this multi-platform. + # We also inherit the overlays that we want to use. + inherit system overlays; + }; + + # bitcoind 27.1 from the pinned input (see inputs above). + bitcoind = nixpkgs-bitcoind.legacyPackages.${system}.bitcoind; + + # The specific Rust toolchain that we use in development shells. + # Matches the `rust-version` declared in Cargo.toml. We use the `minimal` + # profile (rustc, cargo, rust-std) plus clippy and rust-src, but + # deliberately exclude `rustfmt`: this repo's `rustfmt.toml` relies on + # nightly-only options, so formatting is supplied by `rustfmt-nightly` + # below to keep `just fmt`/`just check` consistent with CI's nightly job. + rust-toolchain = pkgs.rust-bin.stable."1.85.1".minimal.override { + extensions = [ + "rust-src" # Needed for the rust-analyzer extension to work. + "clippy" # Linter used by `just check`. + ]; + }; + + # Nightly rustfmt only. `cargo fmt` shells out to whichever `rustfmt` is + # on PATH, so a nightly rustfmt lets the nightly-only options in + # `rustfmt.toml` apply even though cargo/rustc are pinned to stable. + rustfmt-nightly = pkgs.rust-bin.nightly.latest.rustfmt; + + # Esplora/HTTP electrs for the integration tests' Esplora chain source. + # + # We deliberately do NOT use nixpkgs' `blockstream-electrs`: it is a far + # newer build whose initial regtest indexing takes ~80s, blowing past the + # tests' sync timeout. Instead we pin the *exact* prebuilt binary CI uses + # (see scripts/download_bitcoind_electrs.sh) and patch it to run on Nix. + # This keeps local test behaviour identical to CI. + electrs-esplora = + let + rev = "a33e97e1a1fc63fa9c20a116bb92579bbf43b254"; + sources = { + x86_64-linux = { + file = "electrs_linux_esplora_${rev}.zip"; + sha256 = "865e26a96e8df77df01d96f2f569dcf9622fc87a8d99a9b8fe30861a4db9ddf1"; + }; + x86_64-darwin = { + file = "electrs_macos_esplora_${rev}.zip"; + sha256 = "2d5ff149e8a2482d3658e9b386830dfc40c8fbd7c175ca7cbac58240a9505bcd"; + }; + }; + src = + sources.${system} + or (throw "no prebuilt esplora electrs for ${system}"); + in + pkgs.stdenv.mkDerivation { + pname = "electrs-esplora"; + version = "esplora-${builtins.substring 0 9 rev}"; + src = pkgs.fetchurl { + url = "https://github.com/RCasatta/electrsd/releases/download/electrs_releases/${src.file}"; + inherit (src) sha256; + }; + nativeBuildInputs = + [ pkgs.unzip ] ++ pkgs.lib.optional pkgs.stdenv.isLinux pkgs.autoPatchelfHook; + buildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.stdenv.cc.cc.lib ]; + unpackPhase = '' + runHook preUnpack + unzip "$src" + runHook postUnpack + ''; + installPhase = '' + runHook preInstall + install -Dm755 electrs "$out/bin/electrs" + runHook postInstall + ''; + }; + + in + { + # The development shell. Use `nix develop` or direnv to enter it. + devShells.default = pkgs.mkShell { + name = "ldk-node-dev-shell"; + + packages = with pkgs; [ + rustfmt-nightly # Nightly rustfmt; must precede the stable toolchain on PATH. + rust-toolchain # Rust toolchain (no rustfmt; see above). + nodejs # JavaScript runtime, required for MCP tools + mold # Fast linker for Rust/C/C++ + pnpm # Package manager for JavaScript, required for MCP tools + pkg-config # Required by build scripts that link against system libraries + just # Command runner used for `just check`, `just fmt`, etc. + stdenv.cc.cc.lib # C++ standard library for runtime + ]; + + env = { + # OpenSSL configuration for Nix + PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig"; + # C++ standard library path for runtime + LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; + # Integration tests (run with `--cfg no_download`) locate these via env + # rather than downloading generic-linux binaries that can't run on NixOS. + BITCOIND_EXE = "${bitcoind}/bin/bitcoind"; + ELECTRS_EXE = "${electrs-esplora}/bin/electrs"; + }; + + shellHook = '' + echo "LDK Node dev shell" + rustc --version + cargo --version + ''; + }; + } + ); +} diff --git a/justfile b/justfile new file mode 100644 index 000000000..a603aee75 --- /dev/null +++ b/justfile @@ -0,0 +1,23 @@ +default: + @just --list --unsorted + +# Validate: rustfmt check + clippy with warnings denied (matches CI's deny-warnings gate). +check: + cargo fmt --all -- --check + cargo clippy --all-targets -- -D warnings + +# Format all sources in place. +fmt: + cargo fmt --all + +# Apply clippy autofixes across all targets. +fix: + cargo clippy --all-targets --fix --allow-dirty --allow-staged + +# Run library unit tests only. No bitcoind/electrs required. +test: + RUSTFLAGS="-D warnings" cargo test --lib + +# Run full suite incl. integration tests. Needs bitcoind+electrs on PATH (CI's --cfg no_download). +test-all: + RUSTFLAGS="--cfg no_download -D warnings" cargo test