litelib_initialize_new, litelib_initialize_new_from_phrase,
litelib_initialize_existing and litelib_check_server_online had no
catch_unwind (only litelib_execute did), so any panic below them
unwound across the C ABI into the GUI. With rustc 1.63 that is
undefined behaviour; in practice the process aborts with "fatal runtime
error: failed to initiate panic, error 5". The simplest trigger is a
malformed user-entered server URL: get_server_or_default unwraps the
http::Uri parse before anything else runs.
- ffi_guard (next to error_cstring) runs a body under catch_unwind and
turns a panic into "Error: Rust panic in <name>", which the C++ bridge
already treats as a failed call. The three init entry points keep
their extern signatures and #[no_mangle] and call ffi_guard; their old
bodies are now private *_impl functions.
- litelib_check_server_online wraps its body the same way and returns
false on a panic.
- litelib_initialize_existing opens the wallet through
read_from_disk_reporting. After a recovery from the .bak it returns
"OK: recovered from backup; damaged file kept as <name>" instead of
"OK". The C++ side treats any non-empty, non-error string as a
successful open, so this is ABI-compatible.
No ABI or symbol change: the exported symbol inventory
(lite-backend-symbols.txt) is identical. panic = "unwind" stays in the
release profile, and every guard depends on it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The qtlib wrapper's Cargo.toml, the workspace root of the backend build,
had no release profile, so libsilentdragonxlite.a was built with cargo's
defaults: no LTO and 16 codegen units, with the objects of every
dependency copied into the archive.
The release profile now sets opt-level 3, fat LTO and one codegen unit.
panic stays "unwind", written out with a comment: litelib_execute turns
a panic into an error through catch_unwind, and the full-tx fetcher and
the threadpool turn scan-job panics into errors by unwinding. There is
no strip setting: rustc does not link a staticlib, and build.sh strips
the final executable.
Measured, building the same source both ways:
- archive: Linux 126.7 -> 71.5 MB with 1580 -> 1 Rust object files;
Windows 105.9 -> 65.8 MB with 1560 -> 1;
- stripped ObsidianDragonLite: Linux 84,283,856 -> 75,366,184 bytes
(-8.9 MB, -10.6%); Windows exe 87,436,288 -> 79,379,968 bytes
(-8.1 MB, -9.2%). On Linux .text went from 20.0 to 14.8 MB and
.eh_frame from 2.67 to 1.19 MB;
- exported symbols unchanged (blake3_PW and the 8 litelib_* functions);
- a forced panic in the send command's JSON parsing still returns
"Error: Rust panic in litelib_execute", and the next call works;
- lite_smoke --restore-recent, --keys and --encrypt pass with identical
output apart from chain tip and birthday; restore CPU time is
unchanged within noise (115.8-117.2 s before, 111.7-118.8 s after)
and peak RSS dropped from 38.5 to 31.6 MB;
- backend build time: Linux 70 -> 118 s, Windows 54 -> 102 s.
This has no effect on releases until the backend artifacts are rebuilt:
build.sh links the prebuilt build/lite-backend/<platform> archives,
which are still the old non-LTO ones (the Windows one also predates the
recent backend commits). Rebuild them with
scripts/build-lite-backend-artifact.sh from a clean, committed tree.
Not verifiable here: on Windows only the link was checked, with no panic
probe, smoke run, sync or send (inlining can grow stack frames, and
mingw threads get about 2 MB of stack); the macOS artifact was not built
(CARGO_PROFILE_RELEASE_LTO=thin is the fallback if fat LTO is a problem
there); and a send, with its proving, needs a funded wallet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pinned librustzcash / transitive crates (notably traitobject 0.1.0) rely on
pre-1.70 trait coherence and fail to compile on newer rustc (E0119), so the backend
must build with 1.63. Add a rust-toolchain.toml in the vendored backend so rustup
auto-selects 1.63 when cargo runs there — no more manual RUSTUP_TOOLCHAIN=1.63.0.
The pin is scoped to the backend tree (repo-root cargo keeps the default toolchain).
Also symlink the pin into the prepared build root so --silentdragonxlitelib-dir
builds honor it too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Vendor the two local Rust crates that build the lite backend artifact into
third_party/silentdragonxlite/ (the qtlib C-ABI wrapper + the silentdragonxlitelib
core, with proto/res and all the lite-send fixes), and point
build-lite-backend-artifact.sh's default --backend-dir there, so the lite wallet
builds without the upstream SilentDragonXLite repo.
External build inputs are now only the Rust toolchain + git.dragonx.is + crates.io:
- the 6 librustzcash git deps point at the git.dragonx.is/DragonX/librustzcash
mirror (pinned rev acff1444), not git.hush.is;
- the Sapling params are gitignored (not committed, no Git LFS) - the build fetches
them from the git.dragonx.is/DragonX/zcash-params 'sapling-v1' release and verifies
their SHA-256 before rust-embed bakes them in (ensure_sapling_params).
For fully offline builds, cargo vendor into lib/vendor/ and add a vendored-sources
redirect (vendor/ is gitignored; the script symlinks it into the prepared dir).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>