Skip to content

build(guest): remap the absolute paths out of the guest ELF, and pin its sha256 - #993

Open
MauroToscano wants to merge 2 commits into
mainfrom
chore/guest-elf-remap
Open

MauroToscano wants to merge 2 commits into
mainfrom
chore/guest-elf-remap

Conversation

@MauroToscano

Copy link
Copy Markdown
Contributor

What

Two commits on chore/guest-elf-remap:

  • build(guest): scripts/guest_rustflags.py appends --remap-path-prefix for the four real prefixes (workspace, cargo registry, rustup toolchain, sysroot), longest-first, reading each guest's own flags out of its .cargo/config.toml because CARGO_ENCODED_RUSTFLAGS replaces the config's rustflags rather than extending them and the 45 guests carry four different flag sets. make check-ethrex-guest-elf asserts the built ethrex guest's sha256 and prints both digests on a miss.
  • docs(guest): records, measured, what the remapping does not fix.

Why

A guest ELF is a program constant: its Merkle roots, genesis page set and cycle count are read off it and pinned elsewhere. Before this change the build baked in the absolute paths of the machine that produced it (147 /Users/… strings in ethrex.elf, including the rustup toolchain root, which carries the host triple), so two checkouts of one commit produced different bytes and two machines differed by kilobytes, with nothing in the tree able to say which was right.

What it fixes and what it does not

Fixed: every path rustc controls. A build now has zero host paths in the ELF, so the home directory, the registry location, the sysroot and the toolchain path no longer leak in; that was the difference between a Linux box and a macOS laptop building the same sources.

Not fixed, and measured: two differently named checkouts of one commit still give two ELFs (3,948,944 vs 3,950,136 bytes). The residue is cargo's -C metadata disambiguator for path dependencies (the guest crate and lambda-vm-ethrex-crypto), derived from the absolute source path before any flag reaches rustc; git and registry dependencies and build-std are identical across the two builds. Closing it needs a canonical build path (a container or a fixed mount), which is a separate decision.

The sha256 pin is therefore provisional, a property of this commit built in a directory of a particular name. It is wired into nothing that make test or make lint runs, so it cannot produce a failure that looks like drift.

Checks

Both commits are signed. make lint and make fmt are unaffected (no Rust source changes). The Makefile targets are opt-in.

…its sha256

A guest ELF is a program constant. Its Merkle roots, its genesis page set and
its cycle count are read off it and pinned elsewhere, and a recursion guest is
on its way to embedding one of those roots at compile time. All of that assumes
the ELF is a function of the sources.

It was not. Nothing remapped paths, so the build baked in the absolute paths of
the machine that produced it — the workspace directory, the cargo registry
checkout, the rustup toolchain that supplies the build-std sources, the sysroot.
Measured before this change: 147 `/Users/…` strings in `ethrex.elf`, including
the toolchain root, which carries the HOST TRIPLE. Two checkouts of one commit
produced different bytes; two machines differed by kilobytes. Three builds of
"the same" post-#894 sources came out at 3,948,520 / 3,948,504 / 3,952,608 bytes
with three different digests, and nothing in the tree could say which was right
or that anything was wrong.

The failure mode is the quiet one. A constant derived in one worktree is not a
claim about another's guest, and a toolchain bump moves every such constant with
no source change, no code change and no test that fails until a verifier rejects
a valid proof.

`scripts/guest_rustflags.py` appends `--remap-path-prefix` for the four real
prefixes, longest-first so the most specific wins. It reads each guest's OWN
flags out of its `.cargo/config.toml` rather than this repo carrying one list:
`CARGO_ENCODED_RUSTFLAGS` REPLACES the config's rustflags rather than extending
them, and the guests' flag sets are not uniform — four different combinations of
`link-arg=-e main`, `getrandom_backend` and `passes=lower-atomic` across 45
crates — so a blanket value would silently drop flags that decide whether a
guest links or randomises correctly. The config stays the single source of
truth.

`make check-ethrex-guest-elf` is the assertion that makes it stick, and
`assert_sha256` is deliberately not `ensure_verified`: there is nowhere to
refetch a built artifact from, so the only useful behaviours are pass and a
loud, specific failure naming both digests.

Measured after: `ethrex.elf` is 3,948,944 bytes, sha256 `3d34a312…`, with ZERO
`/Users/maurofab` strings.

⚠ This moves the ELF for everyone, so every ELF-derived constant needs
re-deriving with it. Not merged on any campaign branch; the timing is Mauro's.
Two differently named checkouts of this commit still produce different ELFs —
3,948,944 against 3,950,136 bytes — with zero embedded paths in either. The
residue is cargo's `-C metadata` disambiguator, derived from a package's
absolute source path and passed to rustc before any remapping can apply.

The boundary is exact, measured across the two builds: the guest crate and
`lambda-vm-ethrex-crypto`, both PATH packages, get different disambiguators;
`ethrex-trie` (git) and `core` (build-std) are identical. Closing it needs a
canonical build path, which is a bigger decision than a flag.

So the sha256 pin is provisional: a property of this commit built in a
directory of a particular name, not of the commit. Said at the constant, so
nobody wires it into `test` or `lint` and gets a failure that looks like drift.

What the change does fix is the half that crosses machines: the home directory,
the registry location, the sysroot and the rustup toolchain path — the last of
which carries the host triple — no longer appear. That was the 4 KB between a
Linux box and a macOS laptop building the same sources.
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.

1 participant