Skip to content
Merged
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ venv

# Files for launcher
**/.app-compose.json

# Nix cargo home
.nix-cargo/
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ This repository contains the code for the Near MPC node. It is a rewrite of [Nea
- **Nearcore Node**: This repository depends on the nearcore node, included as a submodule in the `/libs` directory.
- **Other Dependencies**: All other dependencies are handled by Cargo.

## Development Environment (Nix)

This repository includes a [flake.nix](flake.nix) file that provides a reproducible development environment using Nix. This environment pre-configures the Rust toolchain, LLVM/Clang tools, NEAR CLI tools, and all necessary system dependencies.
Prerequisites
- **Nix**: [Install Nix](https://nixos.org/download/) with [Flakes enabled](https://nixos.wiki/wiki/Flakes)
- **Docker**: While tools are provided in the shell, the Docker daemon must be running separately on your host system. Docker is required for reproducible builds of the MPC contract.

### Entering the Shell
To activate the development environment, run the following command in the project root:
```shell
nix develop
```

Once you enter the shell, your workspace is immediately ready for development.

## How it works

There are two main parts of the binary: NEAR indexer and MPC signing:
Expand Down
48 changes: 48 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

190 changes: 190 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
{
description = "Rust development environment for NEAR (Workspace)";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};

outputs =
{
self,
nixpkgs,
rust-overlay,
}:
let
lib = nixpkgs.lib;

systems = [
"x86_64-linux"
"aarch64-linux"
Comment thread
gilcu3 marked this conversation as resolved.
Resolved
"aarch64-darwin"
];

pkgsFor =
system:
import nixpkgs {
inherit system;
overlays = [ rust-overlay.overlays.default ];
};

forAllSystems = f: lib.genAttrs systems (system: f (pkgsFor system));

# Helper: compute clang resource include dir for bindgen/wasm.
clangResourceInclude =
llvmPkgs:
let
clangVersion = lib.versions.major llvmPkgs.clang-unwrapped.version;
in
"${llvmPkgs.clang-unwrapped.lib}/lib/clang/${clangVersion}/include";

in
{
devShells = forAllSystems (
pkgs:
let
inherit (pkgs) stdenv;

llvmPkgs = pkgs.llvmPackages_19;

rustToolchain = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml).override {
extensions = [
"rust-src"
"rust-analyzer"
"clippy"
"rustfmt"
];
};

# Local NEAR tooling
cargo-near = pkgs.callPackage ./nix/cargo-near.nix { };
near-cli-rs = pkgs.callPackage ./nix/near-cli-rs.nix { };

# Pinned to CI version
cargoTools = pkgs.callPackage ./nix/cargo-tools.nix { };

libcDev = lib.getDev stdenv.cc.libc;

isX86 = stdenv.hostPlatform.isx86_64;

envCommon = {
# needed for neard's rocksdb build to avoid unsupported CPU features
CXXFLAGS = "-include cstdint" + lib.optionalString isX86 " -msse4.2 -mpclmul";

# WASM Toolchain
CC_wasm32_unknown_unknown = "${llvmPkgs.clang-unwrapped}/bin/clang";
AR_wasm32_unknown_unknown = "${llvmPkgs.llvm}/bin/llvm-ar";
CFLAGS_wasm32_unknown_unknown = "-I${clangResourceInclude llvmPkgs}";

# Bindgen & Paths
LIBCLANG_PATH = "${llvmPkgs.libclang.lib}/lib";
RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library";

BINDGEN_EXTRA_CLANG_ARGS = lib.concatStringsSep " " [
"-I${clangResourceInclude llvmPkgs}"
"-I${libcDev}/include"
"-fno-stack-protector"
];

PYTHONPATH = "./pytest:./nearcore_pytest:./tee_launcher";

# Prevent Cargo from trying to use the system rustup
RUSTUP_TOOLCHAIN = "";
CARGO_HOME = ".nix-cargo";
};

envDarwin = lib.optionalAttrs stdenv.isDarwin {
# Force build scripts to use Nix wrappers (not host clang)
CC = "${stdenv.cc}/bin/cc";
CXX = "${stdenv.cc}/bin/c++";

# cc crate looks for these first on macOS
CC_aarch64_apple_darwin = "${stdenv.cc}/bin/cc";
CXX_aarch64_apple_darwin = "${stdenv.cc}/bin/c++";

AR = "${stdenv.cc.bintools}/bin/ar";
RANLIB = "${stdenv.cc.bintools}/bin/ranlib";
};

dockerTools = with pkgs; [
docker
docker-compose
];

llvmTools = [
pkgs.pkg-config
llvmPkgs.clang
llvmPkgs.libclang
];

rustTools = with pkgs; [
rustToolchain
rustPlatform.bindgenHook
];

nearTools = with pkgs; [
python3Packages.keyring
near-cli-rs
cargo-near
];

miscTools = with pkgs; [
git
zizmor
binaryen
Comment on lines +137 to +138

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to pin versions of these tools to follow ci, I tried cargo make and it failed because of that. new zizmor versions are less permissive. Same happens with these tools:

cargo-binstall
cargo-deny
cargo-insta
cargo-make
cargo-nextest
cargo-shear
cargo-sort

@pbeza pbeza Jan 14, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’d be nice to enforce in CI that these tools use the same versions as defined in .github/workflows/ci.yml. I can open a follow-up issue if we want to tackle this separately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding it now. But it would be the wrong way to go about it to keep enforcing the 1;1 mapping.

If we want to maintain that, then CI might as well use nix

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinned to CI versions except the three packages that are not on CI, so I'll go with latest versions here:

  • cargo-binstall is not pinned to a specific version on CI, so keeping that one as is.
  • cargo-insta (the CLI tool) doesn't exist on CI. The cargo dependency is same as in Cargo.toml.
  • cargo-make not on CI

@pbeza pbeza Jan 14, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding it now. But it would be the wrong way to go about it to keep enforcing the 1;1 mapping.

Why’s that? 🤔

If we want to maintain that, then CI might as well use nix

Why not unify the environment this way? 🤔 We’d finally be able to run CI checks locally in exactly the same way as on remote CI. I actually like this idea.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding it now. But it would be the wrong way to go about it to keep enforcing the 1;1 mapping.

Why’s that? 🤔

Because it adds maintenance overhead to have two update versions for packages in two places. It's easy to miss, and it also causes maintenance burden for whatever script we create to check this.

If we want to maintain that, then CI might as well use nix

Why not? 🤔

You're right to question why not. I 'd like to do this at some point. Then developers and CI have the exact same environment, but it's out of scope for this PR.

I wanted to start small with introducing a flake.nix file to just have a working dev environment as a first step of adding nix support.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right to question why not. I 'd like to do this at some point. Then developers and CI have the exact same environment, but it's out of scope for this PR.

I created an issue for it: #1760.

];

buildLibs =
with pkgs;
[
openssl
zlib
libiconv
snappy
lz4
zstd
bzip2
]
++ lib.optionals stdenv.isLinux [
udev
dbus
];

hardening = [
"fortify"
]
++ lib.optionals stdenv.isDarwin [
"stackprotector"
"strictoverflow"
"format"
"zerocallusedregs"
];

in
{
default = pkgs.mkShell {
strictDeps = true;

packages =
dockerTools ++ llvmTools ++ rustTools ++ cargoTools ++ nearTools ++ miscTools ++ buildLibs;

env = envCommon // envDarwin;

# Remove the hardening added by nix to fix jmalloc compilation error.
# More info: https://github.com/tikv/jemallocator/issues/108
hardeningDisable = hardening;

shellHook = ''
mkdir -p .nix-cargo
export PATH="$PWD/.nix-cargo/bin:$PATH"
printf "\e[32m🦀 NEAR Dev Shell Active\e[0m\n"
'';
};
}
);
};
}
63 changes: 63 additions & 0 deletions nix/cargo-near.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
lib,
stdenv,
rustPlatform,
fetchFromGitHub,
pkg-config,
openssl,
udev,
apple-sdk_14,
}:

rustPlatform.buildRustPackage rec {
pname = "cargo-near";
version = "0.18.0";

src = fetchFromGitHub {
owner = "near";
repo = "cargo-near";
rev = "cargo-near-v${version}";
hash = "sha256-rkqXOfItKO1MmdUFCih6b6g5057iWI6s1JWu/F6r0DY=";
};

cargoHash = "sha256-6GoSN+BrM0sw4rqW+6PIPwkTqZsJDyZAHOm78MtOm90=";

nativeBuildInputs = [
pkg-config
];

buildInputs = [
openssl
]
++ lib.optionals stdenv.isLinux [
udev
]
++ lib.optionals stdenv.isDarwin [
apple-sdk_14
];

env = {
# Prevent the crate from trying to build its own OpenSSL
OPENSSL_NO_VENDOR = 1;
}
// lib.optionalAttrs stdenv.isDarwin {
# Darwin Sonoma / SDK 14 Compatibility
SDKROOT = "${apple-sdk_14}/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk";
MACOSX_DEPLOYMENT_TARGET = "14.0";
CRATE_CC_NO_DEFAULTS = "1";

# Required for crates like wasm-opt-sys that need explicit C++ standard alignment
CMAKE_CXX_STANDARD = "17";
WASM_OPT_CXX_FLAGS = "-std=c++17 -stdlib=libc++";
};

# skip tests as they require network access
doCheck = false;

meta = with lib; {
description = "Cargo extension for reproducible builds of NEAR smart contracts";
homepage = "https://github.com/near/cargo-near";
platforms = platforms.unix;
mainProgram = "cargo near";
};
}
58 changes: 58 additions & 0 deletions nix/cargo-tools.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
lib,
rustPlatform,
fetchCrate,
pkgs,
}:

let
buildTool =
{
pname,
version,
hash,
cargoHash,
}:
rustPlatform.buildRustPackage {
inherit pname version;
src = fetchCrate {
inherit pname version hash;
};
inherit cargoHash;
doCheck = false;
};
in
[
(buildTool {
pname = "cargo-shear";
version = "1.6.0";
hash = "sha256-i27DQnWCMTZ5og5KE2Fes5S7RZy/P3SwS5aEtTUoRd0=";
cargoHash = "sha256-1FuLkcYezcrzzZ7B+n5r4oY/1BI0QYwjOqUjqWopeS0=";
})

(buildTool {
pname = "cargo-nextest";
version = "0.9.106";
hash = "sha256-J8S8Xys/GedOBNZ+MDdxtQq8C1rZOj+qpl+78fcvge0=";
cargoHash = "sha256-wDN09EKLB4jvVGNt1PvrdH9Iqe3EozCFI+wUAFjjGlM=";
})

(buildTool {
pname = "cargo-sort";
version = "2.0.2";
hash = "sha256-U/LakNUSPqj6FmYimi5ZNVJCRiS7zM4Vzvu4Gb3w38Q=";
cargoHash = "sha256-FoFzBf24mNDTRBfFyTEr9Q7sJjUhs0X/XWRGEoierQ4=";
})

(buildTool {
pname = "cargo-deny";
version = "0.18.9";
hash = "sha256-WnIkb4OXutgufNWpFooKQiJ5TNhamtTsFJu8bWyWeR4=";
cargoHash = "sha256-2u1DQtvjRfwbCXnX70M7drrMEvNsrVxsbikgrnNOkUE=";
})

# --- STANDARD NIXPKGS VERSIONS ---
pkgs.cargo-binstall
pkgs.cargo-insta
pkgs.cargo-make
]
Loading