# ObsidianDragon — Coding Standards & Architecture ## Project Identity ObsidianDragon is a native C++17 desktop wallet for the DragonX (DRGX) cryptocurrency. It uses ImGui (immediate-mode GUI) with SDL3, ships an embedded full-node daemon (`dragonxd`), and includes an integrated CPU miner (`xmrig-hac`). Licensed GPLv3. Platforms: Linux (x86_64), Windows (x86_64, cross-compiled via MinGW), macOS (universal arm64+x86_64). ## Code Style ### Naming - **Classes/structs/enums:** `CamelCase` — `RPCClient`, `WalletState`, `NavPage` - **Member variables:** `snake_case_` with trailing underscore — `rpc_`, `connection_status_`, `fast_worker_` - **Functions/methods:** `camelCase` — `tryConnect()`, `isConnected()`, `drainResults()` - **Constants:** `UPPER_SNAKE` for macros, `camelCase` for const vars — `REFRESH_INTERVAL`, `DEFAULT_FEE` - **Enum values:** `CamelCase` — `NavPage::Overview`, `State::Running` - **Type aliases:** `using MainCb = std::function;` ### Formatting - 4-space indentation, no tabs - Opening brace on same line: `void foo() {` - `#pragma once` (not include guards) - Include order: self header, standard library, third-party, project headers ### Memory & Ownership - `std::unique_ptr` for ownership — never raw `new`/`delete` - Raw pointers for non-owning references (e.g., function parameters) - RAII for all resource management (threads, handles, mutexes) ### Documentation - `///` Doxygen comments on public APIs in headers - Implementation files: explain *why*, not *what* - Use `DEBUG_LOGF()` for debug logging, not `printf`/`std::cout` ## Threading Model **Main thread** — ImGui render loop (`App::update()`), all UI code, `drainResults()` callbacks. Never block this thread with network I/O or disk I/O. **`worker_`** (RPCWorker) — General-purpose background thread for batched RPC polling. Executes the `refreshData()` cycle every 5 seconds. **`fast_worker_`** (RPCWorker) — Fast-lane background thread for latency-sensitive operations: console commands, mining hashrate polls. Avoids head-of-line blocking behind main refresh batch. **Monitor threads** — `EmbeddedDaemon` and `XmrigManager` each spawn a monitor thread to read stdout/stderr pipes from their child processes. ### Work Submission Pattern ```cpp // Post work to background thread; return a callback for the main thread worker_->post([this]() -> rpc::RPCWorker::MainCb { json result = rpc_->call("getinfo"); // Runs on worker thread (blocking OK) return [this, result]() { state_.connected = true; // Runs on main thread via drainResults() }; }); ``` `drainResults()` is called each frame in `App::update()` to execute completed callbacks. ## RPC Architecture **Dual-client design:** - `rpc_` + `worker_` — main polling (balance, transactions, sync status) - `fast_rpc_` + `fast_worker_` — console commands, mining stats Both are `RPCClient` instances wrapping libcurl for JSON-RPC over HTTPS. **Callback types:** ```cpp using Callback = std::function; using ErrorCallback = std::function; ``` **Error flow:** RPC errors throw `std::runtime_error` → caught in `doRPC()` → invokes `ErrorCallback` → surfaces via `Notifications::instance().error(msg)`. **Connection state:** `state_.connected` (app-level, set in `onConnected()`) vs `rpc_->isConnected()` (per-client, set after successful `getinfo()`). These can differ — always check the right one for the context. ## Connection Lifecycle ``` [Disconnected] → tryConnect() every 5s → auto-detect DRAGONX.conf (host, port, rpcuser, rpcpassword) → if no config: start embedded daemon → retry → post async rpc_->connect() to worker_ → success: onConnected() → state_.connected = true → auth 401: try .cookie auth → retry → failure: onDisconnected(reason) → may restart daemon ``` ## UI Patterns ### Page Routing `NavPage` enum in `src/ui/sidebar.h` defines all pages. `App::update()` dispatches via switch on `current_page_` to render functions like `RenderBalanceTab(this)` or `console_tab_.render(...)`. ### Dialogs Modal dialogs use `show_*` boolean flags (e.g., `show_import_key_`, `show_backup_`). Set the flag to `true` to open; the dialog renders in `App::update()` and clears the flag when dismissed. ### Notifications ```cpp Notifications::instance().success("Transaction sent"); Notifications::instance().error("Insufficient funds"); ``` Toast-style popups in the bottom-right corner. ### Lock Screen & Loading Overlay - Lock screen gates all interaction when `state_.isLocked()` - Loading overlay shown while daemon isn't ready, gates all tabs except Peers, Console, Settings ## Platform Abstractions Detection: `#ifdef _WIN32` / `#elif __APPLE__` / `#elif __linux__` Platform-specific files live in `src/platform/` (Windows only: DX11 context, backdrop effects). Shared platform utilities in `src/util/platform.h` — `openUrl()`, `getHomeDir()`, `getDragonXDataDir()`. Rendering backends: - Windows: DirectX 11 (`imgui_impl_dx11`) - macOS/Linux: OpenGL 3 (`imgui_impl_opengl3`) + GLAD loader ## Build System CMake 3.20+, C++17. Single `CMakeLists.txt` at root. **FetchContent dependencies:** SDL3, nlohmann/json v3.11.3, toml++ v3.4.0, libcurl (Windows only) **Bundled libraries:** ImGui, GLAD, miniz, libsodium (pre-built per platform), qrcode **macOS:** Universal binary (arm64+x86_64), deployment target 11.0 (Big Sur+). Set `CMAKE_OSX_DEPLOYMENT_TARGET` and `CMAKE_OSX_ARCHITECTURES` before `project()`. **Build commands:** ```bash ./build.sh # Dev build ./build.sh --mac-release # macOS universal .app + DMG ./build.sh --linux-release # Linux AppImage + zip ./build.sh --win-release # Windows cross-compile ``` ## Theme System UI layout values are defined in `res/themes/ui.toml` and accessed via `schema::UI()` — **never hardcode pixel sizes in C++ code**. Skins are self-contained TOML files in `res/themes/` defining color palettes. `scripts/expand_themes.py` merges layout sections from `ui.toml` into each skin at build time. Colors support CSS-style variables: `--primary`, `--surface`, `--on-surface-medium`, resolved by `ColorVarResolver` at runtime. ## Internationalization All user-visible strings use `TR("key")` macro → `dragonx::util::tr()` → lookup in `I18n` singleton. Never hardcode English strings in UI code. Language files: `res/lang/{locale}.json` (runtime) with embedded fallback compiled into binary. Supported: en, es, zh, ru, de, fr, pt, ja, ko. ## Key Rules 1. **Never block the main thread** — all network/disk I/O goes through `worker_->post()` 2. **Never hardcode pixel sizes** — use `ui.toml` schema values via `schema::UI()` 3. **Always use `TR()` for strings** — no hardcoded English in UI rendering code 4. **Use `ICON_MD_*` for icons** — Material Design icon font, never raw Unicode 5. **Use `std::unique_ptr`** — no raw `new`/`delete` in application code 6. **Check the right connection state** — `state_.connected` for app-level, `rpc_->isConnected()` for per-client 7. **Test all three platforms** — build must pass Linux; cross-compile test if touching platform code