From eae55a5a6e12883f6ac0583506bb1fdf1b22505d Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 01:59:57 +0000 Subject: [PATCH 01/11] chore: devbox --- nix/devenv/anchor.nix | 69 ++++++++++++++++++++++++++++ nix/devenv/flake.lock | 61 +++++++++++++++++++++++++ nix/devenv/flake.nix | 104 ++++++++++++++++++++++++++++++++++++++++++ nix/devenv/solana.nix | 72 +++++++++++++++++++++++++++++ 4 files changed, 306 insertions(+) create mode 100644 nix/devenv/anchor.nix create mode 100644 nix/devenv/flake.lock create mode 100644 nix/devenv/flake.nix create mode 100644 nix/devenv/solana.nix diff --git a/nix/devenv/anchor.nix b/nix/devenv/anchor.nix new file mode 100644 index 0000000000..030c4b97ac --- /dev/null +++ b/nix/devenv/anchor.nix @@ -0,0 +1,69 @@ +{ lib +, stdenv +, fetchurl +, autoPatchelfHook +, zlib +, openssl +, glibc +}: + +let + version = "0.31.1"; + + sources = { + x86_64-linux = { + url = "https://github.com/coral-xyz/anchor/releases/download/v${version}/anchor-${version}-x86_64-unknown-linux-gnu"; + hash = "sha256-Xl+PwPdfLD3FzOsIKn9zXQm+IgdUApH/rTcOtbLclZs="; + }; + x86_64-darwin = { + url = "https://github.com/coral-xyz/anchor/releases/download/v${version}/anchor-${version}-x86_64-apple-darwin"; + hash = "sha256-MwGcRwS2x4toDyth5yJEiXKsZ6vokBnyCdCSAGhPTLs="; + }; + aarch64-darwin = { + url = "https://github.com/coral-xyz/anchor/releases/download/v${version}/anchor-${version}-aarch64-apple-darwin"; + hash = "sha256-ljxesAeqMwTXDV4H+Ng5AqHLiQLv7l3aRHzlSLk3lJQ="; + }; + }; + + platform = stdenv.hostPlatform.system; + src = fetchurl { + inherit (sources.${platform}) url hash; + }; + +in stdenv.mkDerivation { + pname = "anchor"; + inherit version src; + + dontUnpack = true; + + nativeBuildInputs = lib.optionals stdenv.isLinux [ + autoPatchelfHook + ]; + + buildInputs = lib.optionals stdenv.isLinux [ + zlib + openssl + stdenv.cc.cc.lib + ]; + + dontConfigure = true; + dontBuild = true; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp $src $out/bin/anchor + chmod +x $out/bin/anchor + runHook postInstall + ''; + + meta = with lib; { + description = "Anchor framework for Solana"; + homepage = "https://anchor-lang.com"; + license = licenses.asl20; + platforms = builtins.attrNames sources; + mainProgram = "anchor"; + }; + + passthru = { inherit version; }; +} diff --git a/nix/devenv/flake.lock b/nix/devenv/flake.lock new file mode 100644 index 0000000000..8ea33045a9 --- /dev/null +++ b/nix/devenv/flake.lock @@ -0,0 +1,61 @@ +{ + "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": 1766070988, + "narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c6245e83d836d0433170a16eb185cefe0572f8b8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "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/nix/devenv/flake.nix b/nix/devenv/flake.nix new file mode 100644 index 0000000000..698d4fd9b0 --- /dev/null +++ b/nix/devenv/flake.nix @@ -0,0 +1,104 @@ +{ + description = "Light Protocol development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + + # Import custom packages + solana = pkgs.callPackage ./solana.nix { }; + anchor = pkgs.callPackage ./anchor.nix { }; + + # Versions (keep in sync with scripts/devenv/versions.sh) + rustVersion = "1.90.0"; + photonCommit = "3dbfb8e6772779fc89c640b5b0823b95d1958efc"; + + in { + packages = { + inherit solana anchor; + default = solana; + }; + + devShells.default = pkgs.mkShell { + packages = [ + # Languages + pkgs.go + pkgs.rustup + pkgs.nodejs_22 + pkgs.pnpm + + # Tools + pkgs.jq + pkgs.redis + pkgs.gnumake + pkgs.pkg-config + pkgs.openssl + + # Solana ecosystem + solana + anchor + ]; + + shellHook = '' + # Environment variables + export REDIS_URL="redis://localhost:6379" + export SBF_OUT_DIR="target/deploy" + + # Solana platform-tools: copy SDK to writable location for cargo-build-sbf + SOLANA_TOOLS_DIR="$HOME/.cache/solana-platform-tools/${solana.version}" + if [ ! -d "$SOLANA_TOOLS_DIR/sbf" ]; then + echo "Setting up Solana platform-tools SDK..." + mkdir -p "$SOLANA_TOOLS_DIR" + cp -r ${solana}/bin/platform-tools-sdk/* "$SOLANA_TOOLS_DIR/" + chmod -R u+w "$SOLANA_TOOLS_DIR" + fi + export SBF_SDK_PATH="$SOLANA_TOOLS_DIR/sbf" + + # Rust toolchain (managed by rustup, not nix) + if ! rustup show active-toolchain 2>/dev/null | grep -q "${rustVersion}"; then + echo "Installing Rust ${rustVersion}..." + rustup install ${rustVersion} + rustup default ${rustVersion} + rustup component add clippy + rustup toolchain install nightly --component rustfmt + fi + + # Photon indexer (installed via cargo) + if ! command -v photon &>/dev/null; then + echo "Installing Photon indexer..." + RUSTFLAGS="-A dead-code" cargo install \ + --git https://github.com/helius-labs/photon.git \ + --rev ${photonCommit} \ + --locked + fi + + # Gnark proving keys (use absolute path) + KEYS_DIR="$(pwd)/prover/server/proving-keys" + if [ ! -d "$KEYS_DIR" ] || [ -z "$(ls -A "$KEYS_DIR" 2>/dev/null)" ]; then + echo "Downloading gnark proving keys..." + (cd prover/server && go run . download --run-mode=forester-test --keys-dir="$KEYS_DIR" --max-retries=10) + fi + + # Node dependencies + if [ ! -d "node_modules" ] || [ -z "$(ls -A node_modules 2>/dev/null)" ]; then + echo "Installing node dependencies..." + pnpm install + fi + + echo "" + echo "Light Protocol devenv activated" + echo " Solana: ${solana.version}" + echo " Anchor: ${anchor.version}" + echo " Rust: ${rustVersion}" + echo "" + ''; + + }; + }); +} diff --git a/nix/devenv/solana.nix b/nix/devenv/solana.nix new file mode 100644 index 0000000000..f0eca45979 --- /dev/null +++ b/nix/devenv/solana.nix @@ -0,0 +1,72 @@ +{ lib +, stdenv +, fetchurl +, autoPatchelfHook +, zlib +, openssl +, udev +, libclang +, llvmPackages +}: + +let + version = "2.2.15"; + + sources = { + x86_64-linux = { + url = "https://github.com/anza-xyz/agave/releases/download/v${version}/solana-release-x86_64-unknown-linux-gnu.tar.bz2"; + hash = "sha256-KfOtGQo9sjB+ZiH0Q0qSXBsQJe8I1Ydr+lqDKanopX4="; + }; + x86_64-darwin = { + url = "https://github.com/anza-xyz/agave/releases/download/v${version}/solana-release-x86_64-apple-darwin.tar.bz2"; + hash = "sha256-uCnX3MkGf3oxKNna8U7+GA4ux9E8Mcsb1WDpkdZc8sQ="; + }; + aarch64-darwin = { + url = "https://github.com/anza-xyz/agave/releases/download/v${version}/solana-release-aarch64-apple-darwin.tar.bz2"; + hash = "sha256-4ycCeVg/EenfWwLO0erK2ryTQ4VSXNWk3nw+W8WQjX8="; + }; + }; + + platform = stdenv.hostPlatform.system; + src = fetchurl { + inherit (sources.${platform}) url hash; + }; + +in stdenv.mkDerivation { + pname = "solana-cli"; + inherit version src; + + sourceRoot = "."; + + nativeBuildInputs = lib.optionals stdenv.isLinux [ + autoPatchelfHook + ]; + + buildInputs = lib.optionals stdenv.isLinux [ + zlib + openssl + stdenv.cc.cc.lib + ] ++ lib.optionals (stdenv.isLinux && udev != null) [ + udev + ]; + + dontConfigure = true; + dontBuild = true; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp -r solana-release/bin/* $out/bin/ + runHook postInstall + ''; + + meta = with lib; { + description = "Solana CLI tools"; + homepage = "https://solana.com"; + license = licenses.asl20; + platforms = builtins.attrNames sources; + mainProgram = "solana"; + }; + + passthru = { inherit version; }; +} From 034535862826c946b307ef2549af44bf27a684b3 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 10:25:24 +0000 Subject: [PATCH 02/11] add nix setup action and workflow --- .github/actions/setup-nix/action.yml | 29 +++++++++++++++++++ .github/workflows/nix-test.yml | 42 ++++++++++++++++++++++++++++ nix/devenv/flake.nix | 11 ++++++++ 3 files changed, 82 insertions(+) create mode 100644 .github/actions/setup-nix/action.yml create mode 100644 .github/workflows/nix-test.yml diff --git a/.github/actions/setup-nix/action.yml b/.github/actions/setup-nix/action.yml new file mode 100644 index 0000000000..4362d39722 --- /dev/null +++ b/.github/actions/setup-nix/action.yml @@ -0,0 +1,29 @@ +name: 'Setup with Nix' +description: 'Install Nix and prepare devshell for Light Protocol' + +inputs: + skip-devshell-build: + description: 'Skip building the devshell (for faster startup when only nix tools needed)' + required: false + default: 'false' + +runs: + using: 'composite' + steps: + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + + - name: Setup Nix Cache + uses: DeterminateSystems/magic-nix-cache-action@main + + - name: Build devshell + if: inputs.skip-devshell-build != 'true' + shell: bash + run: | + # Build and cache the devshell + nix develop ./nix/devenv --command echo "Devshell ready" + + - name: Set environment + shell: bash + run: | + echo "IN_NIX_SHELL=true" >> $GITHUB_ENV diff --git a/.github/workflows/nix-test.yml b/.github/workflows/nix-test.yml new file mode 100644 index 0000000000..1a4e78867f --- /dev/null +++ b/.github/workflows/nix-test.yml @@ -0,0 +1,42 @@ +name: Nix Build Test + +on: + pull_request: + paths: + - 'nix/**' + - '.github/workflows/nix-test.yml' + - '.github/actions/setup-nix/**' + workflow_dispatch: + +jobs: + test-nix-devshell: + name: Test Nix Devshell + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Nix + uses: ./.github/actions/setup-nix + + - name: Verify tools + run: | + nix develop ./nix/devenv --command bash -c ' + echo "=== Tool Versions ===" + solana --version + anchor --version + go version + node --version + pnpm --version + rustc --version + echo "=== All tools working ===" + ' + + - name: Test cargo build-sbf + run: | + nix develop ./nix/devenv --command bash -c ' + cd programs/system + cargo build-sbf 2>&1 | tail -5 + ' diff --git a/nix/devenv/flake.nix b/nix/devenv/flake.nix index 698d4fd9b0..b90f4a9c1d 100644 --- a/nix/devenv/flake.nix +++ b/nix/devenv/flake.nix @@ -26,6 +26,8 @@ }; devShells.default = pkgs.mkShell { + name = "light"; + packages = [ # Languages pkgs.go @@ -39,6 +41,7 @@ pkgs.gnumake pkgs.pkg-config pkgs.openssl + pkgs.starship # Solana ecosystem solana @@ -91,6 +94,14 @@ pnpm install fi + # Mark that we're in the devenv (for custom prompts) + export LIGHT_DEVENV=1 + + # Initialize starship prompt if available and shell is interactive + if [[ $- == *i* ]] && command -v starship &>/dev/null; then + eval "$(starship init bash 2>/dev/null || starship init zsh 2>/dev/null || true)" + fi + echo "" echo "Light Protocol devenv activated" echo " Solana: ${solana.version}" From 5cc29702bcb6bdeca40d626f513b2e98e0bac389 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 10:28:01 +0000 Subject: [PATCH 03/11] native actions/cache --- .github/actions/setup-nix/action.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-nix/action.yml b/.github/actions/setup-nix/action.yml index 4362d39722..af448f0a72 100644 --- a/.github/actions/setup-nix/action.yml +++ b/.github/actions/setup-nix/action.yml @@ -11,10 +11,22 @@ runs: using: 'composite' steps: - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: cachix/install-nix-action@v27 + with: + extra_nix_config: | + experimental-features = nix-command flakes + accept-flake-config = true - - name: Setup Nix Cache - uses: DeterminateSystems/magic-nix-cache-action@main + - name: Cache Nix store + uses: actions/cache@v4 + with: + path: | + /nix/store + /nix/var/nix/profiles + ~/.cache/nix + key: nix-${{ runner.os }}-${{ hashFiles('nix/devenv/flake.lock', 'nix/devenv/*.nix') }} + restore-keys: | + nix-${{ runner.os }}- - name: Build devshell if: inputs.skip-devshell-build != 'true' From 8adbee9ba6e603562dccfdc549fffa60d4d934f6 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 10:28:25 +0000 Subject: [PATCH 04/11] Potential fix for code scanning alert no. 141: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/nix-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/nix-test.yml b/.github/workflows/nix-test.yml index 1a4e78867f..7c1c5be990 100644 --- a/.github/workflows/nix-test.yml +++ b/.github/workflows/nix-test.yml @@ -1,5 +1,8 @@ name: Nix Build Test +permissions: + contents: read + on: pull_request: paths: From e05d2b6496763fe2e92b8ec3011edd474e90b99e Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 10:31:02 +0000 Subject: [PATCH 05/11] ignore optional CUDA/SGX libraries --- nix/devenv/solana.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/nix/devenv/solana.nix b/nix/devenv/solana.nix index f0eca45979..1e0c2da6a2 100644 --- a/nix/devenv/solana.nix +++ b/nix/devenv/solana.nix @@ -53,10 +53,19 @@ in stdenv.mkDerivation { dontConfigure = true; dontBuild = true; + # Ignore missing CUDA/SGX libraries - they're optional performance libs + autoPatchelfIgnoreMissingDeps = [ + "libOpenCL.so.1" + "libsgx_uae_service.so" + "libsgx_urts.so" + ]; + installPhase = '' runHook preInstall mkdir -p $out/bin cp -r solana-release/bin/* $out/bin/ + # Remove optional perf-libs that require CUDA/SGX (not needed for dev/CI) + rm -rf $out/bin/perf-libs runHook postInstall ''; From aaab31497a85788634f901bded1eda9e1a5804a4 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 10:49:06 +0000 Subject: [PATCH 06/11] refactor: remove hardcoded Rust version and streamline toolchain management --- nix/devenv/flake.nix | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/nix/devenv/flake.nix b/nix/devenv/flake.nix index b90f4a9c1d..f9a6163ef1 100644 --- a/nix/devenv/flake.nix +++ b/nix/devenv/flake.nix @@ -16,7 +16,6 @@ anchor = pkgs.callPackage ./anchor.nix { }; # Versions (keep in sync with scripts/devenv/versions.sh) - rustVersion = "1.90.0"; photonCommit = "3dbfb8e6772779fc89c640b5b0823b95d1958efc"; in { @@ -63,12 +62,10 @@ fi export SBF_SDK_PATH="$SOLANA_TOOLS_DIR/sbf" - # Rust toolchain (managed by rustup, not nix) - if ! rustup show active-toolchain 2>/dev/null | grep -q "${rustVersion}"; then - echo "Installing Rust ${rustVersion}..." - rustup install ${rustVersion} - rustup default ${rustVersion} - rustup component add clippy + # Rust: rust-toolchain.toml handles the main toolchain automatically. + # We only need nightly for `cargo +nightly fmt`. + if ! rustup run nightly rustfmt --version &>/dev/null; then + echo "Installing nightly toolchain for rustfmt..." rustup toolchain install nightly --component rustfmt fi @@ -106,7 +103,7 @@ echo "Light Protocol devenv activated" echo " Solana: ${solana.version}" echo " Anchor: ${anchor.version}" - echo " Rust: ${rustVersion}" + echo " Rust: $(rustc --version 2>/dev/null | awk '{print $2}' || echo 'see rust-toolchain.toml')" echo "" ''; From 0da585bb54253d5e8d67bbdb60d4080a2265df12 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 11:16:51 +0000 Subject: [PATCH 07/11] fix rust toolchain management and add cargo wrapper for solana platform-tools --- nix/devenv/flake.lock | 37 ++++++++++++++++++++++++++++++++- nix/devenv/flake.nix | 48 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/nix/devenv/flake.lock b/nix/devenv/flake.lock index 8ea33045a9..2a707014ff 100644 --- a/nix/devenv/flake.lock +++ b/nix/devenv/flake.lock @@ -34,10 +34,45 @@ "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": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1766285238, + "narHash": "sha256-DqVXFZ4ToiFHgnxebMWVL70W+U+JOxpmfD37eWD/Qc8=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "c4249d0c370d573d95e33b472014eae4f2507c2f", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" } }, "systems": { diff --git a/nix/devenv/flake.nix b/nix/devenv/flake.nix index f9a6163ef1..acf2968321 100644 --- a/nix/devenv/flake.nix +++ b/nix/devenv/flake.nix @@ -4,12 +4,47 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; + rust-overlay.url = "github:oxalica/rust-overlay"; }; - outputs = { self, nixpkgs, flake-utils }: + outputs = { self, nixpkgs, flake-utils, rust-overlay }: flake-utils.lib.eachDefaultSystem (system: let - pkgs = import nixpkgs { inherit system; }; + pkgs = import nixpkgs { + inherit system; + overlays = [ rust-overlay.overlays.default ]; + }; + + # Rust version from rust-toolchain.toml + rustVersion = "1.90.0"; + rustToolchain = pkgs.rust-bin.stable.${rustVersion}.default.override { + extensions = [ "clippy" "rust-src" ]; + }; + + # Cargo wrapper that handles `+toolchain` syntax (for cargo-build-sbf compatibility) + cargoWrapper = pkgs.writeShellScriptBin "cargo" '' + if [[ "$1" == +solana ]]; then + # Use platform-tools for SBF compilation + shift + PLATFORM_TOOLS="''${SBF_SDK_PATH:-$HOME/.cache/solana-platform-tools}/dependencies/platform-tools" + if [ -x "$PLATFORM_TOOLS/rust/bin/cargo" ]; then + # Set RUSTC so cargo uses platform-tools rustc (supports -Z flags) + export RUSTC="$PLATFORM_TOOLS/rust/bin/rustc" + export RUSTDOC="$PLATFORM_TOOLS/rust/bin/rustdoc" + exec "$PLATFORM_TOOLS/rust/bin/cargo" "$@" + else + echo "Error: Solana platform-tools not found at $PLATFORM_TOOLS" >&2 + echo "Run cargo-build-sbf once to download platform-tools" >&2 + exit 1 + fi + elif [[ "$1" == +* ]]; then + toolchain="''${1#+}" + shift + exec ${pkgs.rustup}/bin/rustup run "$toolchain" cargo "$@" + else + exec ${rustToolchain}/bin/cargo "$@" + fi + ''; # Import custom packages solana = pkgs.callPackage ./solana.nix { }; @@ -30,7 +65,9 @@ packages = [ # Languages pkgs.go - pkgs.rustup + cargoWrapper # Must be before rustToolchain to shadow cargo + rustToolchain + pkgs.rustup # For `cargo +toolchain` handling pkgs.nodejs_22 pkgs.pnpm @@ -62,8 +99,7 @@ fi export SBF_SDK_PATH="$SOLANA_TOOLS_DIR/sbf" - # Rust: rust-toolchain.toml handles the main toolchain automatically. - # We only need nightly for `cargo +nightly fmt`. + # Install nightly rustfmt via rustup (for `cargo +nightly fmt`) if ! rustup run nightly rustfmt --version &>/dev/null; then echo "Installing nightly toolchain for rustfmt..." rustup toolchain install nightly --component rustfmt @@ -103,7 +139,7 @@ echo "Light Protocol devenv activated" echo " Solana: ${solana.version}" echo " Anchor: ${anchor.version}" - echo " Rust: $(rustc --version 2>/dev/null | awk '{print $2}' || echo 'see rust-toolchain.toml')" + echo " Rust: ${rustVersion}" echo "" ''; From a3055a4872e76618587fa3acff1e29d61ad893bc Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 14:06:44 +0000 Subject: [PATCH 08/11] wip --- .gitignore | 3 ++ nix/devenv/flake.lock | 37 +------------------ nix/devenv/flake.nix | 86 ++++++++++++++++++++++--------------------- scripts/build-sbf.sh | 39 ++++++++++++++++++++ 4 files changed, 88 insertions(+), 77 deletions(-) create mode 100755 scripts/build-sbf.sh diff --git a/.gitignore b/.gitignore index 48f4fbd9be..a20f8bdaba 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,6 @@ output1.txt **/~/ expand.rs + +# Separate target dirs for SBF builds (pinocchio vs anchor features) +target-*/ diff --git a/nix/devenv/flake.lock b/nix/devenv/flake.lock index 2a707014ff..8ea33045a9 100644 --- a/nix/devenv/flake.lock +++ b/nix/devenv/flake.lock @@ -34,45 +34,10 @@ "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", - "rust-overlay": "rust-overlay" - } - }, - "rust-overlay": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1766285238, - "narHash": "sha256-DqVXFZ4ToiFHgnxebMWVL70W+U+JOxpmfD37eWD/Qc8=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "c4249d0c370d573d95e33b472014eae4f2507c2f", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" + "nixpkgs": "nixpkgs" } }, "systems": { diff --git a/nix/devenv/flake.nix b/nix/devenv/flake.nix index acf2968321..807255a0af 100644 --- a/nix/devenv/flake.nix +++ b/nix/devenv/flake.nix @@ -4,53 +4,49 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; - rust-overlay.url = "github:oxalica/rust-overlay"; }; - outputs = { self, nixpkgs, flake-utils, rust-overlay }: + outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let - pkgs = import nixpkgs { - inherit system; - overlays = [ rust-overlay.overlays.default ]; - }; + pkgs = import nixpkgs { inherit system; }; - # Rust version from rust-toolchain.toml - rustVersion = "1.90.0"; - rustToolchain = pkgs.rust-bin.stable.${rustVersion}.default.override { - extensions = [ "clippy" "rust-src" ]; - }; + # Import custom packages + solana = pkgs.callPackage ./solana.nix { }; + anchor = pkgs.callPackage ./anchor.nix { }; - # Cargo wrapper that handles `+toolchain` syntax (for cargo-build-sbf compatibility) - cargoWrapper = pkgs.writeShellScriptBin "cargo" '' - if [[ "$1" == +solana ]]; then - # Use platform-tools for SBF compilation - shift - PLATFORM_TOOLS="''${SBF_SDK_PATH:-$HOME/.cache/solana-platform-tools}/dependencies/platform-tools" - if [ -x "$PLATFORM_TOOLS/rust/bin/cargo" ]; then - # Set RUSTC so cargo uses platform-tools rustc (supports -Z flags) - export RUSTC="$PLATFORM_TOOLS/rust/bin/rustc" - export RUSTDOC="$PLATFORM_TOOLS/rust/bin/rustdoc" - exec "$PLATFORM_TOOLS/rust/bin/cargo" "$@" - else - echo "Error: Solana platform-tools not found at $PLATFORM_TOOLS" >&2 - echo "Run cargo-build-sbf once to download platform-tools" >&2 - exit 1 - fi - elif [[ "$1" == +* ]]; then - toolchain="''${1#+}" + # Smart build-sbf wrapper that uses per-program target dirs to avoid cache invalidation + buildSbfWrapper = pkgs.writeShellScriptBin "build-sbf" '' + set -e + REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" + + # Build a single program with its own target dir + build_program() { + local prog="$1" shift - exec ${pkgs.rustup}/bin/rustup run "$toolchain" cargo "$@" + local name=$(basename "$prog") + echo "==> $prog" + CARGO_TARGET_DIR="$REPO_ROOT/target-$name" cargo build-sbf --manifest-path "$prog/Cargo.toml" "$@" + } + + # If running from workspace root, build each program separately + if [ -f "Cargo.toml" ] && grep -q '^\[workspace\]' "Cargo.toml" 2>/dev/null; then + echo "Building programs with separate target directories..." + for prog in programs/*/; do + if [ -f "$prog/Cargo.toml" ]; then + build_program "$prog" "$@" + fi + done else - exec ${rustToolchain}/bin/cargo "$@" + # Single program build + local name=$(basename "$PWD") + export CARGO_TARGET_DIR="$REPO_ROOT/target-$name" + exec cargo build-sbf "$@" fi ''; - # Import custom packages - solana = pkgs.callPackage ./solana.nix { }; - anchor = pkgs.callPackage ./anchor.nix { }; - # Versions (keep in sync with scripts/devenv/versions.sh) + rustVersion = "1.90.0"; photonCommit = "3dbfb8e6772779fc89c640b5b0823b95d1958efc"; in { @@ -65,9 +61,7 @@ packages = [ # Languages pkgs.go - cargoWrapper # Must be before rustToolchain to shadow cargo - rustToolchain - pkgs.rustup # For `cargo +toolchain` handling + pkgs.rustup pkgs.nodejs_22 pkgs.pnpm @@ -78,10 +72,12 @@ pkgs.pkg-config pkgs.openssl pkgs.starship + pkgs.sccache # Compile cache (helps with different feature combinations) # Solana ecosystem solana anchor + buildSbfWrapper # Smart wrapper with separate target dirs ]; shellHook = '' @@ -89,6 +85,11 @@ export REDIS_URL="redis://localhost:6379" export SBF_OUT_DIR="target/deploy" + # sccache is available but NOT enabled by default + # It helps with different feature combinations but breaks cargo's incremental cache + # Enable manually for CI: export RUSTC_WRAPPER=sccache + export SCCACHE_DIR="$HOME/.cache/sccache" + # Solana platform-tools: copy SDK to writable location for cargo-build-sbf SOLANA_TOOLS_DIR="$HOME/.cache/solana-platform-tools/${solana.version}" if [ ! -d "$SOLANA_TOOLS_DIR/sbf" ]; then @@ -99,9 +100,12 @@ fi export SBF_SDK_PATH="$SOLANA_TOOLS_DIR/sbf" - # Install nightly rustfmt via rustup (for `cargo +nightly fmt`) - if ! rustup run nightly rustfmt --version &>/dev/null; then - echo "Installing nightly toolchain for rustfmt..." + # Rust toolchain (managed by rustup, not nix) + if ! rustup show active-toolchain 2>/dev/null | grep -q "${rustVersion}"; then + echo "Installing Rust ${rustVersion}..." + rustup install ${rustVersion} + rustup default ${rustVersion} + rustup component add clippy rustup toolchain install nightly --component rustfmt fi diff --git a/scripts/build-sbf.sh b/scripts/build-sbf.sh new file mode 100755 index 0000000000..0c372a0628 --- /dev/null +++ b/scripts/build-sbf.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# Smart cargo build-sbf wrapper that uses per-program target directories +# to avoid cache invalidation from different feature combinations. +# +# Usage: +# From workspace root: ./scripts/build-sbf.sh (builds all programs) +# From program dir: ./scripts/build-sbf.sh (builds current program) +# Or add to PATH and use: build-sbf +# + +set -e + +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" + +# Build a single program with its own target dir +build_program() { + local prog="$1" + shift + local name=$(basename "$prog") + echo "==> Building $prog" + CARGO_TARGET_DIR="$REPO_ROOT/target-$name" cargo build-sbf --manifest-path "$prog/Cargo.toml" "$@" +} + +# If running from workspace root, build each program separately +if [ -f "Cargo.toml" ] && grep -q '^\[workspace\]' "Cargo.toml" 2>/dev/null; then + echo "Building programs with separate target directories..." + for prog in programs/*/; do + if [ -f "$prog/Cargo.toml" ]; then + build_program "$prog" "$@" + fi + done +else + # Single program build - use program name for target dir + name=$(basename "$PWD") + export CARGO_TARGET_DIR="$REPO_ROOT/target-$name" + echo "==> Building $name (target: $CARGO_TARGET_DIR)" + exec cargo build-sbf "$@" +fi From 414095fa364c973215c960be893b3e4dbac6d399 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 14:29:24 +0000 Subject: [PATCH 09/11] scripts/test-sbf.sh --- nix/devenv/flake.nix | 39 +++++++++++++++++++++++++++++---------- scripts/test-sbf.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 10 deletions(-) create mode 100755 scripts/test-sbf.sh diff --git a/nix/devenv/flake.nix b/nix/devenv/flake.nix index 807255a0af..9f3f533aef 100644 --- a/nix/devenv/flake.nix +++ b/nix/devenv/flake.nix @@ -20,31 +20,49 @@ set -e REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" - # Build a single program with its own target dir build_program() { - local prog="$1" - shift + local prog="$1"; shift local name=$(basename "$prog") echo "==> $prog" CARGO_TARGET_DIR="$REPO_ROOT/target-$name" cargo build-sbf --manifest-path "$prog/Cargo.toml" "$@" } - # If running from workspace root, build each program separately if [ -f "Cargo.toml" ] && grep -q '^\[workspace\]' "Cargo.toml" 2>/dev/null; then echo "Building programs with separate target directories..." for prog in programs/*/; do - if [ -f "$prog/Cargo.toml" ]; then - build_program "$prog" "$@" - fi + [ -f "$prog/Cargo.toml" ] && build_program "$prog" "$@" done else - # Single program build - local name=$(basename "$PWD") + name=$(basename "$PWD") export CARGO_TARGET_DIR="$REPO_ROOT/target-$name" exec cargo build-sbf "$@" fi ''; + # Smart test-sbf wrapper + testSbfWrapper = pkgs.writeShellScriptBin "test-sbf" '' + set -e + REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" + + test_program() { + local prog="$1"; shift + local name=$(basename "$prog") + echo "==> $prog" + CARGO_TARGET_DIR="$REPO_ROOT/target-$name" cargo test-sbf --manifest-path "$prog/Cargo.toml" "$@" + } + + if [ -f "Cargo.toml" ] && grep -q '^\[workspace\]' "Cargo.toml" 2>/dev/null; then + echo "Testing programs with separate target directories..." + for prog in programs/*/; do + [ -f "$prog/Cargo.toml" ] && test_program "$prog" "$@" + done + else + name=$(basename "$PWD") + export CARGO_TARGET_DIR="$REPO_ROOT/target-$name" + exec cargo test-sbf "$@" + fi + ''; + # Versions (keep in sync with scripts/devenv/versions.sh) rustVersion = "1.90.0"; photonCommit = "3dbfb8e6772779fc89c640b5b0823b95d1958efc"; @@ -77,7 +95,8 @@ # Solana ecosystem solana anchor - buildSbfWrapper # Smart wrapper with separate target dirs + buildSbfWrapper # Smart wrapper: build-sbf + testSbfWrapper # Smart wrapper: test-sbf ]; shellHook = '' diff --git a/scripts/test-sbf.sh b/scripts/test-sbf.sh new file mode 100755 index 0000000000..7a088536eb --- /dev/null +++ b/scripts/test-sbf.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# +# Smart cargo test-sbf wrapper that uses per-program target directories +# to avoid cache invalidation from different feature combinations. +# +# Usage: +# From workspace root: ./scripts/test-sbf.sh (tests all programs) +# From program dir: ./scripts/test-sbf.sh (tests current program) +# + +set -e + +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" + +# Test a single program with its own target dir +test_program() { + local prog="$1" + shift + local name=$(basename "$prog") + echo "==> Testing $prog" + CARGO_TARGET_DIR="$REPO_ROOT/target-$name" cargo test-sbf --manifest-path "$prog/Cargo.toml" "$@" +} + +# If running from workspace root, test each program separately +if [ -f "Cargo.toml" ] && grep -q '^\[workspace\]' "Cargo.toml" 2>/dev/null; then + echo "Testing programs with separate target directories..." + for prog in programs/*/; do + if [ -f "$prog/Cargo.toml" ]; then + test_program "$prog" "$@" + fi + done +else + # Single program test - use program name for target dir + name=$(basename "$PWD") + export CARGO_TARGET_DIR="$REPO_ROOT/target-$name" + echo "==> Testing $name (target: $CARGO_TARGET_DIR)" + exec cargo test-sbf "$@" +fi From 024680000b0ab1291e6e94c791b520774d2cabf7 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 14:50:48 +0000 Subject: [PATCH 10/11] refactor: update Nix installation and caching steps in action.yml --- .github/actions/setup-nix/action.yml | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/.github/actions/setup-nix/action.yml b/.github/actions/setup-nix/action.yml index af448f0a72..3d177abd99 100644 --- a/.github/actions/setup-nix/action.yml +++ b/.github/actions/setup-nix/action.yml @@ -11,28 +11,15 @@ runs: using: 'composite' steps: - name: Install Nix - uses: cachix/install-nix-action@v27 - with: - extra_nix_config: | - experimental-features = nix-command flakes - accept-flake-config = true + uses: DeterminateSystems/nix-installer-action@main - - name: Cache Nix store - uses: actions/cache@v4 - with: - path: | - /nix/store - /nix/var/nix/profiles - ~/.cache/nix - key: nix-${{ runner.os }}-${{ hashFiles('nix/devenv/flake.lock', 'nix/devenv/*.nix') }} - restore-keys: | - nix-${{ runner.os }}- + - name: Enable Nix cache + uses: DeterminateSystems/magic-nix-cache-action@main - name: Build devshell if: inputs.skip-devshell-build != 'true' shell: bash run: | - # Build and cache the devshell nix develop ./nix/devenv --command echo "Devshell ready" - name: Set environment From 0fc8170a98f20579cbd6d3d37666b9493accef40 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Sun, 21 Dec 2025 15:15:03 +0000 Subject: [PATCH 11/11] update rust-overlay --- .github/workflows/nix-test.yml | 1 - nix/devenv/flake.lock | 37 +++++++++++++++++++++++++++++- nix/devenv/flake.nix | 41 +++++++++++++++------------------- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/.github/workflows/nix-test.yml b/.github/workflows/nix-test.yml index 7c1c5be990..a758e9b958 100644 --- a/.github/workflows/nix-test.yml +++ b/.github/workflows/nix-test.yml @@ -33,7 +33,6 @@ jobs: go version node --version pnpm --version - rustc --version echo "=== All tools working ===" ' diff --git a/nix/devenv/flake.lock b/nix/devenv/flake.lock index 8ea33045a9..2a707014ff 100644 --- a/nix/devenv/flake.lock +++ b/nix/devenv/flake.lock @@ -34,10 +34,45 @@ "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": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1766285238, + "narHash": "sha256-DqVXFZ4ToiFHgnxebMWVL70W+U+JOxpmfD37eWD/Qc8=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "c4249d0c370d573d95e33b472014eae4f2507c2f", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" } }, "systems": { diff --git a/nix/devenv/flake.nix b/nix/devenv/flake.nix index 9f3f533aef..0f5e326722 100644 --- a/nix/devenv/flake.nix +++ b/nix/devenv/flake.nix @@ -4,12 +4,26 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; + rust-overlay.url = "github:oxalica/rust-overlay"; }; - outputs = { self, nixpkgs, flake-utils }: + outputs = { self, nixpkgs, flake-utils, rust-overlay }: flake-utils.lib.eachDefaultSystem (system: let - pkgs = import nixpkgs { inherit system; }; + pkgs = import nixpkgs { + inherit system; + overlays = [ rust-overlay.overlays.default ]; + }; + + # Versions (keep in sync with scripts/devenv/versions.sh) + rustVersion = "1.90.0"; + photonCommit = "3dbfb8e6772779fc89c640b5b0823b95d1958efc"; + + # Rust toolchains from rust-overlay (pre-built binaries, fast) + rustStable = pkgs.rust-bin.stable.${rustVersion}.default.override { + extensions = [ "clippy" "rust-src" ]; + }; + rustNightlyFmt = pkgs.rust-bin.nightly.latest.rustfmt; # Import custom packages solana = pkgs.callPackage ./solana.nix { }; @@ -63,10 +77,6 @@ fi ''; - # Versions (keep in sync with scripts/devenv/versions.sh) - rustVersion = "1.90.0"; - photonCommit = "3dbfb8e6772779fc89c640b5b0823b95d1958efc"; - in { packages = { inherit solana anchor; @@ -79,7 +89,8 @@ packages = [ # Languages pkgs.go - pkgs.rustup + rustStable + rustNightlyFmt # For cargo fmt pkgs.nodejs_22 pkgs.pnpm @@ -90,7 +101,6 @@ pkgs.pkg-config pkgs.openssl pkgs.starship - pkgs.sccache # Compile cache (helps with different feature combinations) # Solana ecosystem solana @@ -100,15 +110,9 @@ ]; shellHook = '' - # Environment variables export REDIS_URL="redis://localhost:6379" export SBF_OUT_DIR="target/deploy" - # sccache is available but NOT enabled by default - # It helps with different feature combinations but breaks cargo's incremental cache - # Enable manually for CI: export RUSTC_WRAPPER=sccache - export SCCACHE_DIR="$HOME/.cache/sccache" - # Solana platform-tools: copy SDK to writable location for cargo-build-sbf SOLANA_TOOLS_DIR="$HOME/.cache/solana-platform-tools/${solana.version}" if [ ! -d "$SOLANA_TOOLS_DIR/sbf" ]; then @@ -119,15 +123,6 @@ fi export SBF_SDK_PATH="$SOLANA_TOOLS_DIR/sbf" - # Rust toolchain (managed by rustup, not nix) - if ! rustup show active-toolchain 2>/dev/null | grep -q "${rustVersion}"; then - echo "Installing Rust ${rustVersion}..." - rustup install ${rustVersion} - rustup default ${rustVersion} - rustup component add clippy - rustup toolchain install nightly --component rustfmt - fi - # Photon indexer (installed via cargo) if ! command -v photon &>/dev/null; then echo "Installing Photon indexer..."