Skip to content

Conversation

maru-ava
Copy link

@maru-ava maru-ava commented Sep 26, 2025

Why this should be merged

A nix flake for the firewood ffi library enables deterministic builds both for firewood-go-ethhash and a future nix build of avalanchego.

How this works

  • Adds flake for ffi crate
  • Updates attach-static-libs workflow to build static libs with the flake

How was this tested

  • CI (new ffi-nix job)
  • Locally
    • Install nix:
      • curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
    • cd ffi
    • Build:
      • nix build .#firewood-ffi
    • Test (assuming build step perfomed) outside of a nix dev shell:
      • GOLANG="nix run $PWD#go"
        • Runs the version of golang referenced by the ffi flake
        • Need to capture this before changing directories to result/ffi because result is a nix store symlink so ../../ won't resolve to the ffi path containing the flake
        • Running golang this way instead of with nix develop validates usage of the build output won't require nix develop's shell magic
      • cd result/ffi
      • GOEXPERIMENT=cgocheck2 TEST_FIREWOOD_HASH_MODE=ethhash ${GOLANG} test ./... -v

@maru-ava maru-ava self-assigned this Sep 26, 2025
@maru-ava maru-ava force-pushed the maru/nix-flake branch 6 times, most recently from 1bf2a49 to 4d41947 Compare September 30, 2025 06:55
@maru-ava maru-ava marked this pull request as ready for review September 30, 2025 07:15
Copy link
Member

@rkuris rkuris left a comment

Choose a reason for hiding this comment

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

Definitely don' tknow enough about nix to consider reviewing this, but willing to stamp it after these questions are answered:

  1. Is there any change to the release process? The RELEASE.md file wasn't changed if so.
  2. When dependency updates happen, are any additional steps required?
  3. I noticed all the files in the /nix result directory are dated 1969. Is this expected?
  4. The object files are about half as big, nearly identical text area bug the "others" section is much smaller. Any idea why?

➜ ffi git:(main) ✗ size firewood_ffi*

__TEXT	__DATA	__OBJC	others	dec	hex
827635	38472	0	44544	910651	de53b	firewood_ffi-ac2de0665df5119e.firewood_ffi.36d0102cbf9e788e-cgu.0.rcgu.o
835697	38464	0	1815990	2690151	290c67	firewood_ffi-df1593dabf0edbed.firewood_ffi.eccd115242f4cb72-cgu.0.rcgu.o

I noticed the relocation table is smaller (25899 entries vs 54092). Maybe some new optimization is being done?

@maru-ava
Copy link
Author

maru-ava commented Sep 30, 2025

  1. Is there any change to the release process? The RELEASE.md file wasn't changed if so.

afaik the only change is to the CI job that publishes to firewood-go-ethhash, and I don't see mention of that in RELEASE.md

  1. When dependency updates happen, are any additional steps required?

The only requirement is to keep Cargo.lock up-to-date, and Brandon already added a CI check to ensure PRs won't merge if it's out-of-sync.

  1. I noticed all the files in the /nix result directory are dated 1969. Is this expected?

That is expected - it's the unix epoch (i.e. time=0). Nix sets all built outputs to this time to enable reproducibility, content-addressibility and build caching.

  1. The object files are about half as big, nearly identical text area bug the "others" section is much smaller. Any idea why?

Assuming this is an apples-to-apples comparison (i.e. maxperf and same build args), I would guess there is a difference in the build tooling that nix uses?

@rkuris
Copy link
Member

rkuris commented Sep 30, 2025

Assuming this is an apples-to-apples comparison (i.e. maxperf and same build args), I would guess there is a difference in the build tooling that nix uses?

Yes, it was apples to apples. One concern is that it may affect performance. I'll bring this up at standup.

@rkuris rkuris self-requested a review September 30, 2025 20:56
@maru-ava
Copy link
Author

maru-ava commented Oct 1, 2025

Assuming this is an apples-to-apples comparison (i.e. maxperf and same build args), I would guess there is a difference in the build tooling that nix uses?

Yes, it was apples to apples. One concern is that it may affect performance. I'll bring this up at standup.

Would it make sense to remove the update to the CI job pending qualification of the build artifact with an appropriate performance test?

@rkuris
Copy link
Member

rkuris commented Oct 1, 2025 via email

@maru-ava
Copy link
Author

maru-ava commented Oct 1, 2025

Removed changes to attach-static-libs workflow and added new nix-specific ffi-nix job to ensure coverage.

commonArgs = {
inherit src;
strictDeps = true;
dontStrip = true;
Copy link
Author

Choose a reason for hiding this comment

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

Nix strips debugging details by default, which was resulting in the .a file being ~6MB instead of ~50MB.

ffi/flake.nix Outdated
pname = ffiCargoToml.package.name;
version = workspaceCargoToml.workspace.package.version;

CARGO_PROFILE = "maxperf";
Copy link
Contributor

@demosdemon demosdemon Oct 1, 2025

Choose a reason for hiding this comment

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

this doesn't appear to be working. the size reduction @rkuris noticed is from fewer inlined methods which tells me there's less LTO.

I haven't determined the correct way to set this with rust-overlay, but cargo will use the PROFILE environment variable if --profile is not provided on the command line.

EDIT: that appears to be incorrect. looks like there is no environment variable that cargo will use to infer the profile and it must be provided in the cli invocation. https://doc.rust-lang.org/cargo/reference/profiles.html#profile-selection

Copy link
Contributor

@demosdemon demosdemon Oct 1, 2025

Choose a reason for hiding this comment

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

I see CARGO_PROFILE is actually a parameter to crane's mkCargoDerivation which is wrapped by buildDepsOnly and buildPackage. So, I'm not entirely sure why this profile doesn't appear to work.

Copy link
Author

@maru-ava maru-ava Oct 1, 2025

Choose a reason for hiding this comment

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

As per the most recent code comment, the reason for the reduction in size was due to nix automatically stripping debugging symbols (which is the default for nix). I've corrected that, and the .a files are now [edit: almost] identical in size.

I also believe that CARGO_PROFILE is being respected. This var is for configuring crane as per its api docs (search for CARGO_PROFILE) rather than intended for direct consumption by cargo. This can be verified by the following invocation:

  • cd ffi && nix build .#firewood-ffi --print-build-logs --rebuild 2>&1 | grep -i "cargo build"

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I didn't realize the change to not strip came after Ron's comment.

@rkuris rkuris self-requested a review October 1, 2025 18:00
ffi/flake.nix Outdated
# Install the static library and header
postInstall = ''
mkdir -p $out/lib $out/include
cp target/*/libfirewood_ffi.a $out/lib/ || cp target/release/libfirewood_ffi.a $out/lib/
Copy link
Contributor

Choose a reason for hiding this comment

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

the * should probably be replaced with maxperf as the target directory is deterministic on the profile used. If the resulting artifact isn't in the maxperf directory, then we're using the wrong profile.

Copy link
Author

Choose a reason for hiding this comment

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

Done

@maru-ava
Copy link
Author

maru-ava commented Oct 1, 2025

fwiw I added a script to validate build equivalency. Not sure whether it makes sense to merge it, I just wanted to have a common reference point of comparison.

@maru-ava
Copy link
Author

maru-ava commented Oct 1, 2025

I tried to run the build equivalency script on macos but there are some issues with the macos support that I think should be corrected before merge.

@maru-ava
Copy link
Author

jemalloc appears to be introducing non-deterministic build behavior in CI but not locally. Updating to run make invocations serially appears to resolve this.

@maru-ava maru-ava requested a review from rkuris October 15, 2025 15:34
maru-ava and others added 21 commits October 17, 2025 09:19
Set MAKEFLAGS=-j1 to force sequential build of vendored jemalloc in
tikv-jemallocator. The vendored jemalloc has race conditions during
parallel builds causing non-deterministic symbol generation on x86_64
(NixOS/nixpkgs#380852).

Using MAKEFLAGS instead of NUM_JOBS ensures only the make invocation
for jemalloc is affected, while Cargo continues to build Rust crates
in parallel.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Copy link
Member

@rkuris rkuris left a comment

Choose a reason for hiding this comment

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

Good to go, please rebase and merge. Maintenance question should just get answered here. Other stuff are nits that don't need fixing.

Comment on lines 69 to 76
# Use grep with -E for better portability (avoid -P which isn't available on macOS)
if [[ "$OSTYPE" == "darwin"* ]]; then
grep -Eo "$RELOC_PATTERN" "$TMPDIR/nix-relocs.txt" | sort | uniq -c > "$TMPDIR/nix-reloc-types.txt"
grep -Eo "$RELOC_PATTERN" "$TMPDIR/cargo-relocs.txt" | sort | uniq -c > "$TMPDIR/cargo-reloc-types.txt"
else
grep -oP "$RELOC_PATTERN" "$TMPDIR/nix-relocs.txt" | sort | uniq -c > "$TMPDIR/nix-reloc-types.txt"
grep -oP "$RELOC_PATTERN" "$TMPDIR/cargo-relocs.txt" | sort | uniq -c > "$TMPDIR/cargo-reloc-types.txt"
fi
Copy link
Member

Choose a reason for hiding this comment

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

nit: Aren't there some grep options that work on both platforms?

otherwise, I would have preferred GREPFLAGS=-Eo and GREPFLAGS=-Op based on $OSTYPE and then combining all those into single statements.

Copy link
Author

@maru-ava maru-ava Oct 18, 2025

Choose a reason for hiding this comment

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

Updated to minimize duplication: 15742d2

Comment on lines +251 to +252
- uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 #v20
- uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 #v13
Copy link
Member

Choose a reason for hiding this comment

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

Questions: How and when are these hardcoded shas updated? I'm sure dependabot won't tell us when they update. Should we add something to the release checklist to see if they should be updated?

What happens if someone finds a security vulnerability in these packages?

Copy link
Author

Choose a reason for hiding this comment

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

dependabot can, in fact, tell you to update. I just checked, though, and it's not yet configured for this repo. This is what needs to be in .github/dependabot.yml:

  - package-ecosystem: github-actions
    directory: "/"
    schedule:
      interval: weekly
    open-pull-requests-limit: 0 # Disable non-security version updates

As per ava-labs/avalanchego#3822, specifying SHAs for 3rd party actions (i.e. not provided by github) is best practice to avoid supply chain attack. A high-profile incident earlier this year galvanized awareness of the problem.

Copy link
Author

@maru-ava maru-ava Oct 18, 2025

Choose a reason for hiding this comment

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

Updated dependabot config: dc0f60b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants