macdeployqt bundles Qt frameworks but not the plain @rpath/*.dylib brew
deps of its image plugins, so a no-Homebrew Mac couldn't load webp. Add a
Qt-safe pass that resolves @rpath/*.dylib (never @rpath/*.framework) from
brew, copies them in, rewrites load paths, and fails the build if any
remain. Sign step now re-signs by Mach-O type (not exec bit) so the
install_name_tool-modified plugins get valid signatures.
The 100%-linked app dynamically referenced brew's libboost_*.dylib, which
macdeployqt failed to bundle — the app would fail to launch on any Mac
without Homebrew (notarization doesn't check runtime dylib resolution).
Static boost matches how guix/depends release builds work and removes the
runtime dependency entirely.
monero's static libs built fine, but the feather target includes monero
headers pulling boost/variant.hpp, and clang doesn't search
/opt/homebrew/include by default (modern BoostConfig leaves
Boost_INCLUDE_DIRS empty).
brew's protobuf pulls Abseil headers that require C++17, breaking the
feather compile (DEVICE_TREZOR_READY gates the protobuf link). Trezor
hardware does not support Wownero, so this removes a useless dependency
rather than working around it — the Linux lane only tolerates it because
its depends system pins an old protobuf.
- Sync Progress value had both left and horizontalCenter anchors (drifted center)
- 20pt labels in 30px rows collided; now 14pt matching the top-left monitors
- hashrate/uptime/height values auto-fit their pixel-art frames (HorizontalFit)
- 'uptime' -> 'Uptime'
Dispatch-only workflow in .gitea/workflows (GitHub ignores the
directory): brew dependencies, native cmake build with the embedded
wownerod fetched per-arch, unsigned app bundle artifact. Runs on the
mac runner whose work dir lives on DataSSD and is outside every backup
path. Signing/notarization follows once a Developer ID Application
certificate is provisioned as repo secrets.
Field report: a send sat 'in mempool' for two days while the network had
never seen it (Tor down at send time defeats both the multi-broadcast and
the embedded daemon's exclusive --tx-proxy relay), locking the change.
Three additive changes, all strictly local (no txid is ever queried
against an external service):
- onMultiBroadcast now counts relay responses; if no node accepted the
broadcast within 45s the user is told immediately and offered the
existing rebroadcast path, instead of silence.
- A periodic local history scan warns once per outgoing tx that has been
pending for more than 25 minutes, again offering rebroadcast (which
already reconnects to a fresh node first).
- On DaemonManager::synced, still-pending outgoing txs are re-announced
from the wallet's own tx cache; a restarted embedded node's pool has
forgotten them.
On top of Lucas's #119 (--db-sync-mode safe):
- DaemonManager: age out the crash-retry budget (m_restarts) so legit node
toggles/restarts don't trip "maximum retries exceeded" after ~4 spawns over a
session; the cap now only bites a genuine rapid crash-loop.
- DaemonManager: clear the m_stopping latch on start(), so the crash auto-restart
keeps working after the node has been toggled off then on (it was a one-shot
before).
- bump version 5.0.2 -> 5.0.3.
- wizard: hide the hardware-device wallet option (wownero has no Ledger/Trezor
support; inherited Feather cruft).
- bump version 5.0.1 -> 5.0.2.
v5.0.2 also rebuilds the Linux AppImage in an ubuntu:24.04 container (glibc 2.39)
so it runs on Ubuntu 24.04 / Mint / Debian — v5.0.1's AppImage was built on
glibc 2.43 and would not start elsewhere. No wallet-code change: wallets created
on pre-table-fix builds carry a stale restore height (blank balance); the fix is
to re-restore from seed.
restore_heights_wownero_mainnet.txt was last updated 2023-12-15 (h587048).
For wallets created after that, RestoreHeightLookup::dateToHeight extrapolates
forward at 288 blk/day; 2.5y past the last anchor overshoots the chain tip, so
the computed restore height lands ABOVE the current height. The wallet then
skips output-scan on every real block => received funds are never recorded,
while the tx pool still shows them: coins appear pending, then vanish.
Same bug class as 8686e9bf (which fixed the block-time CONSTANT from monero's
120s/720-per-day to wownero's 300s/288); here the constant was right but the
TABLE went stale. Regenerated with contrib/generate-restore-heights/heights.py
to h849000 (2026-06-19). Verified dateToHeight < tip for all dates 2019..today.
Windows crash chain (exposed by the embedded-node default):
- main.cpp: force the QtQuick software renderer. The Mining tab's QQuickWidget
drove the default RHI/GL path and faulted (0xc0000005) on broken-GL hosts
(VirtualBox VMSVGA), crashing the app and orphaning the embedded node.
Real hardware was unaffected.
- ChildProcessGuard + DaemonManager/TorManager: kernel-level die-with-parent
(Windows Job Object KILL_ON_JOB_CLOSE / Linux PR_SET_PDEATHSIG) so the
embedded wownerod and bundled tor never survive a wowlet exit or crash.
- DaemonManager: verify-before-adopt via get_info (nettype/height) instead of
trusting a bare open RPC port, so a stale/orphan node is never adopted.
Node/Tor lifecycle + remote-node connectivity:
- config: torPrivacyLevel default -> allTorExceptNode. NEVER sync blocks over
Tor; the wallet's node connection is always clearnet. Tor is only for tx
broadcast, so remote nodes work with or without Tor.
- nodes: add Nodes::reconnect() (clear failure blocklist + force reconnect);
node/Tor toggle handlers use it so a transient outage no longer strands the
wallet at "Disconnected".
- MainWindow/SettingsDialog: reconnect on node/Tor toggle and on the async
daemonStateChanged (closes the start() race; a freshly-toggled local node
connects immediately).
- TorManager: reset retry/unpack state in init() so a system<->bundled Tor
re-toggle can start again; quiesce on stop(). Linux unpackBins() rework
(mkpath + presence-based unpack + graceful return-false), getVersion() arg
fix, and a missing-binary start guard.
- build.yml: derive TOR_VERSION from the embedded tor binary (a hardcoded
bundle number made unpackBins rewrite Tor every launch).
- depends/funcs.mk: confine cross-cmake find_package to the depends sysroot so
host -dev libraries don't leak into the build.
v5.0.0 ships Windows x86_64 + Linux x86_64. arm64/riscv64 (Qt static-link gap) and macOS deferred to v5.0.1. continue-on-error keeps the cross job from failing the release run while I keep iterating it.
libxkbcommon 1.13.1 meson.build adds empty pkgconfig vars when xkeyboard-config is absent from the cross sysroot (XKEYBOARD_CONFIG_ROOT='') while has_extensions_directories is true -> meson hard-errors at pkgconfig.generate. Pass non-empty -Dxkb-config-(un)versioned-extensions-path.
Add restore-keys to all 4 depends cache restores: a busted exact key (any packages/* edit) now falls back to the newest prefix match, so make resumes from the partial built tree instead of rebuilding the static-Qt6 toolchain from scratch.
The find debug showed wayland-scanner.pc at <build_prefix>/lib/x86_64-linux-gnu/pkgconfig (multiarch layout), not lib/pkgconfig or share/pkgconfig. Add that path to the pkg-config vars so cross-meson finds the native scanner. Keeps native Wayland support (no disabling).
wayland-scanner.pc is a noarch .pc -> build_prefix/share/pkgconfig, not lib/pkgconfig, so the earlier PKG_CONFIG_PATH_FOR_BUILD missed it. Add share/pkgconfig to LIBDIR/PATH/PATH_FOR_BUILD + a find to log the real location.
Target wayland (-Dscanner=false) resolves the host scanner via dependency(..., native: true), which uses meson's BUILD-machine pkg-config — not pointed at build_prefix. Add PKG_CONFIG_PATH_FOR_BUILD=build_prefix + a [binaries] wayland-scanner in the cross-file. Fixes 'Dependency wayland-scanner not found' on aarch64/riscv64.
Cross-build wowlet via depends for aarch64/riscv64 (reusing the zeromq/ICU/qt/testlib fixes), embed the matching wownerod + depends-built tor, package an AppImage via contrib/AppImage/build-appimage.sh (its hardcoded /feather runtime path relativized to GITHUB_WORKSPACE). Cached per-host, save-always.
feather.exe links ${ICU_LIBRARIES}, set by the monero submodule's static-build branch assuming depends ships ICU + libiconv. Feather's depends doesn't, and its depends boost is --without-icu, so nothing references ICU/iconv symbols — the mingw link failed on missing -licu*/-liconv. Clear ICU_LIBRARIES when CMAKE_CROSSCOMPILING; native (system boost, built with ICU) unchanged.
wowlet.exe reached 27% then hit 'zmq.h: No such file' — feather strips zeromq from depends (its wallet does not use zmq) but wownero cryptonote_core/net does. Port the wownero zeromq.mk + patch, register it in packages. Also switch the depends caches to restore + save(if:always) so the completed toolchain banks even when the wowlet build fails (auto post-save is skipped on job failure).
Cross qtdeclarative builds tools/qmltestrunner (QtQuickTest, needs testlib) and demands a matching HOST tool; the host's -no-feature-testlib left it without one, failing 'Configuring qtdeclarative' with 'Failed to find host tool Qt6::qmltestrunner'.
Disk fix let it run 50min (vs ~10min) before the runner lost communication again -> OOM during the parallel Qt6 compile, not disk. Drop both builds to -j2 and add a 10G swapfile for headroom. Slower but should complete + cache depends for fast future runs.
First run was killed mid depends build (runner lost communication = CPU/Memory/disk starvation). Inside a container we cannot reclaim the runner's pre-installed bloat, leaving the static-Qt6 build only ~14G. Run on ubuntu-latest directly, free ~25G (dotnet/android/ghc/CodeQL), sudo the apt steps.
Builds wowlet.exe via contrib/depends (static Qt6 + tor), embeds wownerod.exe from the wownero mingw release, packages a .zip. Caches the depends tree so only the first run pays the ~1h toolchain cost. Tor shipped loose next to the exe (TOR_INSTALLED).
- TorInfoDialog: when wowlet reuses an already-running external/system Tor (isLocalTor), show 'Connected (using external Tor)' instead of the misleading 'Not running'.
- mining.qml: raise + tighten the Block Height / Sync Progress block so it sits in the dark header bar instead of clipping the scene art (first pass, may need a small tweak).
- DaemonManager --tx-proxy now uses the Tor that is actually running (torManager()->isLocalTor()) instead of the stored useLocalTor preference, which selected the wrong SOCKS port (managed 19450 vs system 9050) and silently stalled outbound tx broadcasts.
- Embedded node: nodeDataDir setting points wownerod at an existing chain (e.g. ~/.wownero) to skip a full re-sync; empty keeps the managed isolated default.
- mining.qml: tell the user mining waits until the node is synced.
So wowlet works for users without a system Tor. The build fetches the
tor-expert-bundle (linux x86_64), patchelfs the tor binary + its libs to
$ORIGIN, and passes -DTOR_DIR/-DTOR_VERSION so cmake embeds them into
:/assets/tor and sets HAS_TOR_BIN=1. wowlet then extracts + manages its own
Tor daemon -> remote node connections route over Tor out of the box.
feather's websocket-node filter drops every non-onion node once the Tor privacy
level flips to onion-preferred (after initial sync) — it assumes an onion node
ecosystem. wownero's public nodes are clearnet, so the Settings list went empty
and autoConnect had nothing eligible -> Disconnected. Keep clearnet nodes
eligible in every proxy mode (routed over Tor's SOCKS proxy when Tor is on, so
still private); only hide onion/i2p nodes when their anonymity mode isn't active.
The feather websocket is disabled (no WOW backend); replace it with a Tor-routed
HTTP poll of https://wownero.org/nodes/api/nodes/wallet (the live, health-checked
node-map feed). Builds the managed node list from the feed's plain-http nodes
(skips SSL-only nodes feather can't reach), falls back to the bundled nodes.json
if the feed is unreachable, refreshes hourly. So users who don't run a local node
get a fresh, working remote-node list instead of a stale hardcoded one.