diff --git a/.dockerignore b/.dockerignore index 6000c736f3..c20776424b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,6 +12,8 @@ !pnpm-lock.yaml !rust-toolchain.toml !**/*.sh +!flake.nix +!flake.lock # Explicitly ignore build artifacts everywhere target/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53d7932c4f..5f9ecc6806 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -463,6 +463,20 @@ jobs: target/debug/pack_e3_params if-no-files-found: error + check-nix-flake: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: cachix/install-nix-action@v30 + with: + extra_nix_config: | + experimental-features = nix-command flakes + # if the following fails it means some of our git dependencies or bb has updated + # to fix this basically what you need to do here is copy the actual hashes + # into the flake.nix where those hashes are expected. if you want to do this locally + # install the nix package manager and try running the scripts below. + - run: bash ./scripts/nix-versions.sh # display bad versions when deps change + ciphernode_integration_test: needs: [detect_changes, integration_prebuild, build_enclave_cli, build_sdk] if: needs.detect_changes.outputs.ciphernode_e2e == 'true' diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index b281d87dec..3a39eb76b0 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -138,6 +138,28 @@ jobs: cache-to: | type=gha,mode=max,scope=e3-support + build-nix-flake: + name: Build Nix Flake + runs-on: ubuntu-latest + needs: validate-and-prepare + steps: + - uses: actions/checkout@v6 + - uses: cachix/install-nix-action@v30 + with: + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/install-nix-action@v4 + - uses: cachix/cachix-action@v15 + with: + name: enclave + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + # if the following fails it means some of our git dependencies or bb has updated + # to fix this basically what you need to do here is copy the actual hashes + # into the flake.nix where those hashes are expected. if you want to do this locally + # install the nix package manager and try running the scripts below. + - run: bash ./scripts/nix-versions.sh # display bad versions when deps change + - run: nix build .#default # build the nix flake + build-binaries: name: Build Binaries (${{ matrix.os_name }}-${{ matrix.arch }}) runs-on: ${{ matrix.os }} @@ -371,8 +393,11 @@ jobs: publish-rust-crates, publish-npm-packages, download-circuits, + build-nix-flake, ] - if: always() && needs.validate-and-prepare.result == 'success' && needs.build-binaries.result == 'success' + if: + always() && needs.validate-and-prepare.result == 'success' && needs.build-binaries.result == 'success' && needs.build-nix-flake.result + == 'success' steps: - name: Checkout uses: actions/checkout@v6 diff --git a/crates/cli/build.rs b/crates/cli/build.rs index fc319d9aa5..23239d653c 100644 --- a/crates/cli/build.rs +++ b/crates/cli/build.rs @@ -7,24 +7,26 @@ use std::process::Command; fn main() { - // Try to get local git SHA first - let output = Command::new("git") - .args(&["rev-parse", "--short=9", "HEAD"]) - .output(); - - let git_sha = match output { - Ok(output) if output.status.success() => String::from_utf8(output.stdout) - .unwrap_or_else(|_| "unknown".to_string()) - .trim() - .to_string(), - _ => { - // Fallback to remote commit hash - get_remote_commit_hash().unwrap_or_else(|| "unknown".to_string()) + let git_sha = if let Ok(sha) = std::env::var("GIT_SHA") { + sha + } else { + // Try to get local git SHA first + let output = Command::new("git") + .args(&["rev-parse", "--short=9", "HEAD"]) + .output(); + match output { + Ok(output) if output.status.success() => String::from_utf8(output.stdout) + .unwrap_or_else(|_| "unknown".to_string()) + .trim() + .to_string(), + _ => get_remote_commit_hash().unwrap_or_else(|| "unknown".to_string()), } }; // Set environment variable for compilation println!("cargo:rustc-env=GIT_SHA={}", git_sha); + println!("cargo:rerun-if-env-changed=GIT_SHA"); + // Rebuild if git HEAD changes println!("cargo:rerun-if-changed=.git/HEAD"); } diff --git a/docs/pages/installation.mdx b/docs/pages/installation.mdx index 26d63f50b7..8c98d01d01 100644 --- a/docs/pages/installation.mdx +++ b/docs/pages/installation.mdx @@ -67,6 +67,41 @@ enclaveup uninstall enclaveup uninstall --system ``` +## Install with Nix + +If you use [Nix](https://nixos.org/) with flakes enabled, you can get a complete runtime environment +with no additional dependencies — Nix handles everything including installing the `bb` backend. + +Get a devshell directly without installing it: + +```bash +nix develop github:gnosisguild/enclave/{branch,tag,commit} +``` + +This will build from source using the nix package manager and provide a runtime environemnt for +enclave. It might take some time but the result will be cached on your local nix store for future +execution. + +```bash +❯ nix develop github:gnosisguild/enclave/ry/v0.1.16 +❯ enclave --version +enclave 0.1.16 +❯ bb --version +3.0.0-nightly.20251104 +❯ echo $E3_CUSTOM_BB +/nix/store/6da5va1malbj4pjrzn5lan6n51m4hg9h-bb/bin/bb +``` + +NOTE: On first run, Nix will ask you to trust our binary cache. Say yes to both prompts to download +pre-built binaries instead of building from source: + +``` +do you want to allow configuration setting 'extra-substituters' to be set to '...'? y +do you want to permanently mark this value as trusted? y +``` + +If you decline, everything still works — it just builds from source, which takes longer. + ## Manual Installation If you prefer to install manually: diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..c993e94b50 --- /dev/null +++ b/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": 1772542754, + "narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8c809a146a140c5c8806f13399592dbcb1bb5dc4", + "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/flake.nix b/flake.nix new file mode 100644 index 0000000000..ed3f3b74bb --- /dev/null +++ b/flake.nix @@ -0,0 +1,180 @@ +{ + description = "Enclave"; + nixConfig = { + extra-substituters = ["https://enclave.cachix.org"]; + extra-trusted-public-keys = ["enclave.cachix.org-1:B5SynR85iX/TRueDpZu4dh1xVR8lNfKoAaVWZkux1ss="]; + }; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = { + self, + nixpkgs, + flake-utils, + }: let + # define the version hashes. everytime we change dependencies these need to change + noirHash = "sha256-RoeWaqgFwr8A4HAlu5DzuxrNrexMolIZG14fHQA0KmM="; + fheHash = "sha256-dS8LcKDI/D9ycsRXbQnMVkUc2ymFBFL8kDrEtRGuHNI="; + vfsHash = "sha256-+d8RFk7UgOXDCE/LizCTV+UX/Xm/1mYWrR7W0l6mAl8="; + # bb version + checksums driven from versions.json + versionsJson = builtins.fromJSON (builtins.readFile ./crates/zk-prover/versions.json); + bbVersion = versionsJson.required_bb_version; + bbHashes = versionsJson.bb_checksums; + in + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + }; + noirSrc = pkgs.fetchFromGitHub { + owner = "noir-lang"; + repo = "noir"; + rev = "v1.0.0-beta.16"; + hash = noirHash; + }; + bbPlatform = + if pkgs.stdenv.isLinux + then + if pkgs.stdenv.isAarch64 + then "arm64-linux" + else "amd64-linux" + else if pkgs.stdenv.isDarwin + then + if pkgs.stdenv.isAarch64 + then "arm64-darwin" + else "amd64-darwin" + else throw "Unsupported platform"; + bbBin = pkgs.stdenv.mkDerivation { + pname = "barretenberg"; + version = bbVersion; + src = pkgs.fetchurl { + url = "https://github.com/gnosisguild/aztec-packages/releases/download/v${bbVersion}/barretenberg-${bbPlatform}.tar.gz"; + sha256 = bbHashes.${bbPlatform}; + }; + nativeBuildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [pkgs.autoPatchelfHook]; + buildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [pkgs.stdenv.cc.cc.lib]; + sourceRoot = "."; + installPhase = '' + mkdir -p $out/bin + install -D -m755 bb $out/bin/bb + ''; + meta = { + description = "Barretenberg proving system"; + homepage = "https://github.com/AztecProtocol/aztec-packages"; + }; + }; + bb = + if pkgs.stdenv.isLinux + then + pkgs.buildFHSEnv { + name = "bb"; + targetPkgs = p: [bbBin p.stdenv.cc.cc.lib]; + runScript = "${bbBin}/bin/bb"; + } + else bbBin; + wrapped-bb = + if pkgs.stdenv.isLinux + then + pkgs.writeShellScriptBin "bb" '' + exec ${pkgs.steam-run}/bin/steam-run ${bb}/bin/bb "$@" + '' + else bb; + e3-cli = pkgs.rustPlatform.buildRustPackage { + pname = "e3-cli"; + version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version; + src = ./.; + GIT_SHA = self.rev or self.dirtyRev or "unknown"; + GIT_COMMIT = "unknown"; + GIT_DIRTY = "false"; + preBuild = '' + for d in $(find /build -type d -name 'noirc_driver*'); do + if [ -d "$d/src" ]; then + cp -r ${noirSrc}/noir_stdlib "$d/../../noir_stdlib" + fi + done + export HOME=$(mktemp -d) + git config --global user.email "nix@nix" + git config --global user.name "nix" + git init + git add -A + git commit -m "nix build" --allow-empty + ''; + cargoLock = { + lockFile = ./Cargo.lock; + outputHashes = builtins.listToAttrs ( + map (name: { + inherit name; + value = noirHash; + }) [ + "acir-1.0.0-beta.16" + "acir_field-1.0.0-beta.16" + "acvm-1.0.0-beta.16" + "acvm_blackbox_solver-1.0.0-beta.16" + "bn254_blackbox_solver-1.0.0-beta.16" + "brillig-1.0.0-beta.16" + "brillig_vm-1.0.0-beta.16" + "fm-1.0.0-beta.16" + "iter-extended-1.0.0-beta.16" + "nargo-1.0.0-beta.16" + "noir_greybox_fuzzer-1.0.0-beta.16" + "noir_protobuf-1.0.0-beta.16" + "noirc_abi-1.0.0-beta.16" + "noirc_arena-1.0.0-beta.16" + "noirc_artifacts-1.0.0-beta.16" + "noirc_driver-1.0.0-beta.16" + "noirc_errors-1.0.0-beta.16" + "noirc_evaluator-1.0.0-beta.16" + "noirc_frontend-1.0.0-beta.16" + "noirc_printable_type-1.0.0-beta.16" + "noirc_span-1.0.0-beta.16" + ] + ++ map (name: { + inherit name; + value = fheHash; + }) [ + "fhe-0.1.0-beta.7" + "fhe-math-0.1.0-beta.7" + "fhe-traits-0.1.0-beta.7" + "fhe-util-0.1.0-beta.7" + ] + ++ map (name: { + inherit name; + value = vfsHash; + }) [ + "vfs-0.12.1" + ] + ); + }; + buildAndTestSubdir = "crates/cli"; + nativeBuildInputs = [ + pkgs.pkg-config + pkgs.git + pkgs.pnpm + pkgs.nodejs + pkgs.jq + pkgs.solc + ]; + buildInputs = [ + pkgs.openssl + ]; + meta = { + description = "e3 CLI"; + license = pkgs.lib.licenses.lgpl3Only; + }; + }; + in { + packages.default = e3-cli; + packages.cli = e3-cli; + packages.bb = wrapped-bb; + devShells.default = pkgs.mkShell { + packages = [ + e3-cli + wrapped-bb + ]; + shellHook = '' + export E3_CUSTOM_BB="${wrapped-bb}/bin/bb" + ''; + }; + }); +} diff --git a/scripts/nix-versions.sh b/scripts/nix-versions.sh new file mode 100755 index 0000000000..11a61be988 --- /dev/null +++ b/scripts/nix-versions.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +val() { grep "$1 = " flake.nix | head -1 | sed 's/.*"\(.*\)".*/\1/'; } +NOIR_REV=$(grep 'rev = ' flake.nix | head -1 | sed 's/.*"\(.*\)".*/\1/') +VERSIONS_JSON="./crates/zk-prover/versions.json" +BB_VER=$(jq -r '.required_bb_version' "$VERSIONS_JSON") +FAIL=0 +check() { + local name="$1" url="$2" expected="$3" unpack="${4:-}" + printf "%-35s" "$name" + got=$(nix hash convert --to sri --hash-algo sha256 "$(nix-prefetch-url $unpack --type sha256 "$url" 2>/dev/null)") + if [[ "$got" == "$expected" ]]; then echo "$name is correct ✅" + else echo "❌ expected $expected got $got"; FAIL=1; fi +} +check "noir" \ + "https://github.com/noir-lang/noir/archive/${NOIR_REV}.tar.gz" \ + "$(val noirHash)" --unpack + +# COMMENTING OUT WHILE WE ARE MISSING THE CORRECT VERSION +# WAITING FOR UPGRADE OF BB VERSION +# for p in amd64-linux arm64-linux amd64-darwin arm64-darwin; do +for p in amd64-linux; do + hex=$(jq -r ".bb_checksums[\"${p}\"]" "$VERSIONS_JSON") + sri=$(nix hash convert --to sri --hash-algo sha256 "$hex") + check "bb-${p}" \ + "https://github.com/gnosisguild/aztec-packages/releases/download/v${BB_VER}/barretenberg-${p}.tar.gz" \ + "$sri" +done +exit $FAIL