risc0 compiles its Metal (GPU) prover kernels by invoking `xcrun metal` /
`xcrun metallib`. Under nix, the darwin stdenv exports DEVELOPER_DIR and
SDKROOT pointing at its own SDK, which makes xcrun look for the `metal`
tool in the wrong place and fail with:
error: cannot execute tool 'metal' due to missing Metal Toolchain;
use: xcodebuild -downloadComponent MetalToolchain
...even when a working Metal Toolchain is installed (the same call succeeds
in a clean environment where those vars are unset).
Wrap xcrun with a small shim, placed first in PATH, that clears
DEVELOPER_DIR/SDKROOT for `metal`/`metallib` invocations only — so they
resolve the system Xcode Metal Toolchain — while every other xcrun call
passes through with the nix environment intact. This makes wallet-ffi
build with real GPU prover kernels on macOS, with no --override-input
workaround needed downstream.
Note: on recent macOS the Metal Toolchain is a per-user component, so
`xcodebuild -downloadComponent MetalToolchain` must have been run by the
building user (and builds still require `--option sandbox false`).
The indexer's storage location was the `home` field of IndexerConfig, used only to derive the RocksDB dir. Defaulting to "." meant it landed in the process CWD — fine for the standalone service, but wrong when the indexer runs embedded in a logos_host subprocess (RocksDB ended up in an arbitrary/unwritable dir). Storage location is an operational concern the host should own, not something baked into a user-editable config.
Remove `home` from IndexerConfig and pass the storage directory explicitly:
- core: `IndexerCore::new(config, storage_dir)` derives `<storage_dir>/rocksdb`.
- ffi: `start_indexer(runtime, config_path, storage_dir)`; null/empty storage_dir falls back to ".". Lets a host (e.g. a Logos module's instance persistence path) own where state lives.
- service: `run_server(config, storage_dir, port)` + a `--data-dir` flag (default ".") on the binary, preserving current behaviour.
- drop `home` from the committed indexer config JSONs and the test fixtures.
BREAKING CHANGE: `start_indexer` gains a `storage_dir` parameter and IndexerConfig no longer has a `home` field.
The indexer FFI test helper borrowed `ctx.runtime()` via `Runtime::from_borrowed` and then moved `ctx` (and its by-value `tokio::runtime::Runtime` field) into the tuple returned from `setup()`. That move relocates the runtime, leaving the raw pointer the indexer stored dangling. Sync queries never touch the runtime, so they passed; `query_account` is the only path that `block_on`s it, so it dereferenced freed stack memory → SIGSEGV (hence only the two `indexer_ffi_state_consistency*` tests crashed).
Pass a null runtime so the FFI creates and owns its own — the same lifetime path the production module uses (`start_indexer(nullptr, …)`) — instead of borrowing a runtime whose address isn't stable across the move.