diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-01 17:14:12 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-01 17:14:12 +0000 |
| commit | b4f0bc693ef7175702f82bcb2110b627922e8cbd (patch) | |
| tree | 73435feb1a076dfba94d8143d7d7b7784908c82f /src/gui.cpp | |
| parent | a1d867ecbcfc9e218408d0a11863a450243a01f9 (diff) | |
| parent | 6aa3dade77632f13189d2a3ef29897f29a5f9572 (diff) | |
Merge upstream v1.2.20 into the fork
Merges upstream tag v1.2.20 (6aa3dade) into our 1.2.19+sec tree. The merge
base is bc3de30's descendant 9e39a50 -- upstream's own v1.2.19 -- so this is
an ordinary three-way merge, not a replay. Five conflict blocks in four
files, all resolved below.
No consensus change. CheckBlock, ConnectBlock, DisconnectBlock, ConnectInputs,
AcceptBlock, AcceptTransaction, GetNextWorkRequired and GetBlockValue hash
identical to v1.2.19; script.cpp and script.h are byte-identical on both
sides. main.cpp is +3 lines and main.h +2, all wallet-backend plumbing.
rpc.cpp is untouched, so the payout ledger arrives unchanged.
Makefile, VERSION. OURS, renumbered. 1.2.20+sec, for the same reason 1.2.19
carried +sec: this tree is not the upstream release of that number and the
string names every release artifact.
Makefile, AppImage recipe. OURS for the AppDir path, THEIRS for the bundled
library. Upstream's hunk reverts the icon paths to a hardcoded
/tmp/bitflash.AppDir, which is the local-user pre-placement hazard the fork
moved out of /tmp in the first place; taking their side wholesale would have
reintroduced it silently, inside a conflict about something else. The AppDir
stays $(APPDIR), and libsqlite3.so.0 joins the bundled list, which the new
backend genuinely needs.
src/Makefile, src/makefile.mingw, HEADERS. BOTH. Ours drops market.h,
theirs adds wallet_sqlite.h; the resolution does both. NODE_OBJS auto-merged
correctly in both files -- obj/wallet_sqlite.o present, obj/market.o still
gone -- and was verified rather than assumed, because that line has trapped
this fork before.
src/selftest.cpp, known-tests list. BOTH, union. Upstream adds eight
wallet-storage tests, we keep payout-ledger. The dispatch chain itself
auto-merged and still routes payout-ledger to RunPayoutLedgerSelfTest.
Hardening verified intact after merge: the TLS 1.2 floor in nostr.cpp, the
/rvrelay pin, opt-in managed Tor, strict sig3-on-onion descriptor
verification, and the marketplace removal. Upstream shipped no build logs or
__pycache__ this time; the three added files are docs/storage.md and
src/wallet_sqlite.{cpp,h}.
The SQLite backend this release introduces is NOT enabled here. An existing
wallet.dat resolves to Berkeley DB on every branch of the new selection
logic, and the conversion wizard is GUI-only and not compiled into the
headless node. The review findings that gate ever turning it on -- the
non-atomic backend marker, the connection-wide WriteHDMaster transaction,
and the encrypt-swap crash window -- are recorded on the tracker, not fixed
here.
Diffstat (limited to 'src/gui.cpp')
| -rw-r--r-- | src/gui.cpp | 239 |
1 files changed, 232 insertions, 7 deletions
diff --git a/src/gui.cpp b/src/gui.cpp index 8dcb854..2a7f350 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -11,6 +11,11 @@ | |||
| 11 | #include <ctime> | 11 | #include <ctime> |
| 12 | #include <cstdio> | 12 | #include <cstdio> |
| 13 | #include <sstream> | 13 | #include <sstream> |
| 14 | #ifdef _WIN32 | ||
| 15 | #include <shellapi.h> // ShellExecuteA, to open the website in the browser | ||
| 16 | #else | ||
| 17 | #include <unistd.h> | ||
| 18 | #endif | ||
| 14 | #include <iomanip> | 19 | #include <iomanip> |
| 15 | #include <atomic> | 20 | #include <atomic> |
| 16 | #include <mutex> | 21 | #include <mutex> |
| @@ -172,7 +177,11 @@ static bool PathIsInsideDataDir(const std::string& strPath) | |||
| 172 | 177 | ||
| 173 | static void SetDefaultBackupPath() | 178 | static void SetDefaultBackupPath() |
| 174 | { | 179 | { |
| 175 | std::string path = DefaultBackupDir() + "/wallet-backup-" + BackupTimeSuffix() + ".dat"; | 180 | // Match the extension to the live backend: BackupWallet copies wallet.sqlite |
| 181 | // under the SQLite backend and wallet.dat under Berkeley DB, so a ".dat" | ||
| 182 | // default name would put SQLite contents in a misleadingly-named file. | ||
| 183 | const char* pszExt = WalletSQLiteRuntimeActive() ? ".sqlite" : ".dat"; | ||
| 184 | std::string path = DefaultBackupDir() + "/wallet-backup-" + BackupTimeSuffix() + pszExt; | ||
| 176 | strncpy(g_backupPath, path.c_str(), sizeof(g_backupPath)-1); | 185 | strncpy(g_backupPath, path.c_str(), sizeof(g_backupPath)-1); |
| 177 | g_backupPath[sizeof(g_backupPath)-1] = '\0'; | 186 | g_backupPath[sizeof(g_backupPath)-1] = '\0'; |
| 178 | } | 187 | } |
| @@ -1254,11 +1263,11 @@ static void DrawWalletSafetyDialog() | |||
| 1254 | } | 1263 | } |
| 1255 | ImGui::Text("Phrase-backed spendable balance: %s BTF", | 1264 | ImGui::Text("Phrase-backed spendable balance: %s BTF", |
| 1256 | FmtMoney(g_recoveryAudit.nRecoverableCredit).c_str()); | 1265 | FmtMoney(g_recoveryAudit.nRecoverableCredit).c_str()); |
| 1257 | ImGui::Text("Wallet.dat-only spendable balance: %s BTF", | 1266 | ImGui::Text("Not phrase-backed spendable balance: %s BTF", |
| 1258 | FmtMoney(g_recoveryAudit.nLegacyCredit).c_str()); | 1267 | FmtMoney(g_recoveryAudit.nLegacyCredit).c_str()); |
| 1259 | ImGui::Text("Phrase-backed immature mining rewards: %s BTF", | 1268 | ImGui::Text("Phrase-backed immature mining rewards: %s BTF", |
| 1260 | FmtMoney(g_recoveryAudit.nRecoverableImmatureCredit).c_str()); | 1269 | FmtMoney(g_recoveryAudit.nRecoverableImmatureCredit).c_str()); |
| 1261 | ImGui::Text("Wallet.dat-only immature mining rewards: %s BTF", | 1270 | ImGui::Text("Not phrase-backed immature mining rewards: %s BTF", |
| 1262 | FmtMoney(g_recoveryAudit.nLegacyImmatureCredit).c_str()); | 1271 | FmtMoney(g_recoveryAudit.nLegacyImmatureCredit).c_str()); |
| 1263 | if (!g_recoveryAudit.fDeriveComplete) | 1272 | if (!g_recoveryAudit.fDeriveComplete) |
| 1264 | { | 1273 | { |
| @@ -1272,8 +1281,8 @@ static void DrawWalletSafetyDialog() | |||
| 1272 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.75f, 0.25f, 1.0f)); | 1281 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.75f, 0.25f, 1.0f)); |
| 1273 | ImGui::TextWrapped( | 1282 | ImGui::TextWrapped( |
| 1274 | "Some coins are on keys the phrase does not reproduce. " | 1283 | "Some coins are on keys the phrase does not reproduce. " |
| 1275 | "Keep wallet.dat backups until that balance has been moved to a " | 1284 | "Keep a file backup of this wallet until that balance has been " |
| 1276 | "phrase-backed address."); | 1285 | "moved to a phrase-backed address."); |
| 1277 | ImGui::PopStyleColor(); | 1286 | ImGui::PopStyleColor(); |
| 1278 | } | 1287 | } |
| 1279 | else if (HaveHDSeed() && | 1288 | else if (HaveHDSeed() && |
| @@ -1369,16 +1378,38 @@ static void DrawDiagnosticsDialog() | |||
| 1369 | ImGui::End(); | 1378 | ImGui::End(); |
| 1370 | } | 1379 | } |
| 1371 | 1380 | ||
| 1381 | static void OpenURL(const char* pszUrl) | ||
| 1382 | { | ||
| 1383 | #ifdef _WIN32 | ||
| 1384 | ShellExecuteA(NULL, "open", pszUrl, NULL, NULL, SW_SHOWNORMAL); | ||
| 1385 | #else | ||
| 1386 | std::string cmd = std::string("xdg-open '") + pszUrl + "' >/dev/null 2>&1 &"; | ||
| 1387 | int r = system(cmd.c_str()); | ||
| 1388 | (void)r; | ||
| 1389 | #endif | ||
| 1390 | } | ||
| 1391 | |||
| 1372 | static void DrawAboutDialog() | 1392 | static void DrawAboutDialog() |
| 1373 | { | 1393 | { |
| 1374 | if (!g_showAbout) return; | 1394 | if (!g_showAbout) return; |
| 1375 | ImGui::SetNextWindowSize(ImVec2(380.0f, 170.0f), ImGuiCond_Always); | 1395 | ImGui::SetNextWindowSize(ImVec2(380.0f, 205.0f), ImGuiCond_Always); |
| 1376 | ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), | 1396 | ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), |
| 1377 | ImGuiCond_Always, ImVec2(0.5f, 0.5f)); | 1397 | ImGuiCond_Always, ImVec2(0.5f, 0.5f)); |
| 1378 | if (ImGui::Begin("About Bitflash", &g_showAbout, | 1398 | if (ImGui::Begin("About Bitflash", &g_showAbout, |
| 1379 | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) | 1399 | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) |
| 1380 | { | 1400 | { |
| 1381 | ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), "Bitflash BTF v1.1.0"); | 1401 | ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), |
| 1402 | "Bitflash BTF v" BITFLASH_VERSION_STRING); | ||
| 1403 | ImGui::Spacing(); | ||
| 1404 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.40f, 0.70f, 1.0f, 1.0f)); | ||
| 1405 | ImGui::TextUnformatted("https://bitflash.network"); | ||
| 1406 | ImGui::PopStyleColor(); | ||
| 1407 | if (ImGui::IsItemHovered()) | ||
| 1408 | { | ||
| 1409 | ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); | ||
| 1410 | if (ImGui::IsMouseClicked(0)) | ||
| 1411 | OpenURL("https://bitflash.network"); | ||
| 1412 | } | ||
| 1382 | ImGui::Spacing(); | 1413 | ImGui::Spacing(); |
| 1383 | ImGui::TextWrapped( | 1414 | ImGui::TextWrapped( |
| 1384 | "CPU-only cryptocurrency. RandomX proof of work. " | 1415 | "CPU-only cryptocurrency. RandomX proof of work. " |
| @@ -1391,6 +1422,184 @@ static void DrawAboutDialog() | |||
| 1391 | ImGui::End(); | 1422 | ImGui::End(); |
| 1392 | } | 1423 | } |
| 1393 | 1424 | ||
| 1425 | // First-run offer to move a Berkeley DB wallet to the SQLite backend. Only the | ||
| 1426 | // button actions touch anything: "Convert" exports wallet.dat to wallet.sqlite | ||
| 1427 | // and records the backend marker (wallet.dat is left untouched, so a restart | ||
| 1428 | // picks up SQLite while the old file stays as a fallback); "Keep Berkeley DB" | ||
| 1429 | // just records that choice so the offer does not return; "Decide later" leaves | ||
| 1430 | // no marker and asks again next start. | ||
| 1431 | static bool g_showBackendWizard = false; | ||
| 1432 | static std::string g_wizardStatus; | ||
| 1433 | static bool g_wizardConverted = false; | ||
| 1434 | static int g_restartArgc = 0; | ||
| 1435 | static char** g_restartArgv = NULL; | ||
| 1436 | |||
| 1437 | #ifdef _WIN32 | ||
| 1438 | // Quote one argument so CommandLineToArgvW parses it back to exactly this | ||
| 1439 | // string: only backslashes that immediately precede a double quote (including | ||
| 1440 | // the closing one) are doubled, so ordinary Windows paths are not mangled. | ||
| 1441 | static std::string QuoteArgWin(const std::string& a) | ||
| 1442 | { | ||
| 1443 | if (!a.empty() && a.find_first_of(" \t\"") == std::string::npos) | ||
| 1444 | return a; | ||
| 1445 | std::string r = "\""; | ||
| 1446 | size_t bs = 0; | ||
| 1447 | for (size_t i = 0; i < a.size(); i++) | ||
| 1448 | { | ||
| 1449 | if (a[i] == '\\') { bs++; continue; } | ||
| 1450 | if (a[i] == '"') { r.append(bs * 2 + 1, '\\'); r += '"'; bs = 0; continue; } | ||
| 1451 | r.append(bs, '\\'); bs = 0; r += a[i]; | ||
| 1452 | } | ||
| 1453 | r.append(bs * 2, '\\'); | ||
| 1454 | r += "\""; | ||
| 1455 | return r; | ||
| 1456 | } | ||
| 1457 | #endif | ||
| 1458 | |||
| 1459 | // Relaunch Bitflash with the same arguments and datadir, then ask this instance | ||
| 1460 | // to exit -- but only once the relaunch has actually started, so a failure never | ||
| 1461 | // leaves the user with no node running. The new instance waits (-restartwait) | ||
| 1462 | // before it opens the network port and the block index, so this one is gone | ||
| 1463 | // first and they never fight over the same files. | ||
| 1464 | static void RestartApplication() | ||
| 1465 | { | ||
| 1466 | bool fLaunched = false; | ||
| 1467 | #ifdef _WIN32 | ||
| 1468 | char exePath[MAX_PATH]; | ||
| 1469 | if (GetModuleFileNameA(NULL, exePath, MAX_PATH) == 0) | ||
| 1470 | return; | ||
| 1471 | std::string strCmd = QuoteArgWin(exePath); | ||
| 1472 | bool fHasDataDir = false; | ||
| 1473 | for (int i = 1; i < g_restartArgc; i++) | ||
| 1474 | { | ||
| 1475 | std::string a = g_restartArgv[i] ? g_restartArgv[i] : ""; | ||
| 1476 | if (a.find("-datadir=") == 0 || a.find("/datadir=") == 0) | ||
| 1477 | fHasDataDir = true; | ||
| 1478 | strCmd += " " + QuoteArgWin(a); | ||
| 1479 | } | ||
| 1480 | if (!fHasDataDir) | ||
| 1481 | strCmd += " " + QuoteArgWin("-datadir=" + GetAppDir()); | ||
| 1482 | strCmd += " -restartwait"; | ||
| 1483 | |||
| 1484 | std::vector<char> cmdBuf(strCmd.begin(), strCmd.end()); | ||
| 1485 | cmdBuf.push_back('\0'); | ||
| 1486 | STARTUPINFOA si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); | ||
| 1487 | PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); | ||
| 1488 | if (CreateProcessA(NULL, &cmdBuf[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) | ||
| 1489 | { | ||
| 1490 | CloseHandle(pi.hProcess); | ||
| 1491 | CloseHandle(pi.hThread); | ||
| 1492 | fLaunched = true; | ||
| 1493 | } | ||
| 1494 | #else | ||
| 1495 | pid_t pid = fork(); | ||
| 1496 | if (pid == 0) | ||
| 1497 | { | ||
| 1498 | // Child: wait for the parent to release the port and files, then re-exec. | ||
| 1499 | // /proc/self/exe is the reliable absolute path; argv[0] may be relative | ||
| 1500 | // or a bare name that execv() cannot resolve. | ||
| 1501 | sleep(2); | ||
| 1502 | char exePath[4096]; | ||
| 1503 | ssize_t len = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1); | ||
| 1504 | if (len > 0) | ||
| 1505 | { | ||
| 1506 | exePath[len] = '\0'; | ||
| 1507 | execv(exePath, g_restartArgv); | ||
| 1508 | } | ||
| 1509 | if (g_restartArgv) | ||
| 1510 | execv(g_restartArgv[0], g_restartArgv); | ||
| 1511 | _exit(127); | ||
| 1512 | } | ||
| 1513 | fLaunched = (pid > 0); | ||
| 1514 | #endif | ||
| 1515 | |||
| 1516 | if (fLaunched) | ||
| 1517 | { | ||
| 1518 | fShutdown = true; | ||
| 1519 | if (glfwGetCurrentContext()) | ||
| 1520 | glfwSetWindowShouldClose(glfwGetCurrentContext(), true); | ||
| 1521 | } | ||
| 1522 | else | ||
| 1523 | g_wizardStatus = "Could not relaunch automatically -- please restart " | ||
| 1524 | "Bitflash yourself to switch to the SQLite wallet."; | ||
| 1525 | } | ||
| 1526 | |||
| 1527 | static void DrawBackendWizardDialog() | ||
| 1528 | { | ||
| 1529 | if (!g_showBackendWizard) return; | ||
| 1530 | ImGui::SetNextWindowSize(ImVec2(560.0f, 0.0f), ImGuiCond_Always); | ||
| 1531 | ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), | ||
| 1532 | ImGuiCond_Always, ImVec2(0.5f, 0.5f)); | ||
| 1533 | if (ImGui::Begin("Wallet Storage", &g_showBackendWizard, | ||
| 1534 | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) | ||
| 1535 | { | ||
| 1536 | if (g_wizardConverted) | ||
| 1537 | { | ||
| 1538 | ImGui::TextColored(ImVec4(0.35f, 1.0f, 0.45f, 1.0f), "Converted to SQLite."); | ||
| 1539 | ImGui::TextWrapped("%s", g_wizardStatus.c_str()); | ||
| 1540 | ImGui::Spacing(); | ||
| 1541 | ImGui::TextWrapped( | ||
| 1542 | "The switch takes effect when Bitflash restarts. Until then it is " | ||
| 1543 | "still running on the old Berkeley DB wallet. Your wallet.dat is " | ||
| 1544 | "kept untouched as a fallback."); | ||
| 1545 | ImGui::Spacing(); | ||
| 1546 | if (ImGui::Button("Restart Now", ImVec2(140.0f, 0.0f))) | ||
| 1547 | RestartApplication(); | ||
| 1548 | ImGui::SameLine(); | ||
| 1549 | if (ImGui::Button("Later", ImVec2(120.0f, 0.0f))) | ||
| 1550 | g_showBackendWizard = false; | ||
| 1551 | ImGui::Spacing(); | ||
| 1552 | ImGui::TextDisabled( | ||
| 1553 | "If you keep mining before restarting, new coins go to the old " | ||
| 1554 | "wallet until you switch."); | ||
| 1555 | } | ||
| 1556 | else | ||
| 1557 | { | ||
| 1558 | ImGui::TextWrapped( | ||
| 1559 | "Bitflash can store your wallet in a new SQLite format: a single " | ||
| 1560 | "file that is easier to back up and does not depend on the " | ||
| 1561 | "database/ directory beside it."); | ||
| 1562 | ImGui::Spacing(); | ||
| 1563 | ImGui::TextWrapped( | ||
| 1564 | "Your current Berkeley DB wallet (wallet.dat) is kept exactly as it " | ||
| 1565 | "is -- nothing is deleted, and you can go back to it at any time. " | ||
| 1566 | "The change takes effect after you restart."); | ||
| 1567 | ImGui::Spacing(); | ||
| 1568 | if (ImGui::Button("Convert to SQLite", ImVec2(180.0f, 0.0f))) | ||
| 1569 | { | ||
| 1570 | int nCopied = 0; | ||
| 1571 | std::string strError; | ||
| 1572 | if (DoConvertWalletToSQLite(nCopied, strError)) | ||
| 1573 | { | ||
| 1574 | g_wizardStatus = | ||
| 1575 | strprintf("%d record(s) copied to wallet.sqlite.", nCopied); | ||
| 1576 | g_wizardConverted = true; | ||
| 1577 | } | ||
| 1578 | else | ||
| 1579 | g_wizardStatus = "Conversion failed: " + strError; | ||
| 1580 | } | ||
| 1581 | ImGui::SameLine(); | ||
| 1582 | if (ImGui::Button("Keep Berkeley DB", ImVec2(160.0f, 0.0f))) | ||
| 1583 | { | ||
| 1584 | WriteWalletBackendMarker("bdb"); | ||
| 1585 | g_showBackendWizard = false; | ||
| 1586 | } | ||
| 1587 | ImGui::SameLine(); | ||
| 1588 | if (ImGui::Button("Decide later", ImVec2(120.0f, 0.0f))) | ||
| 1589 | g_showBackendWizard = false; | ||
| 1590 | |||
| 1591 | if (!g_wizardStatus.empty()) | ||
| 1592 | { | ||
| 1593 | ImGui::Spacing(); | ||
| 1594 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.45f, 0.35f, 1.0f)); | ||
| 1595 | ImGui::TextWrapped("%s", g_wizardStatus.c_str()); | ||
| 1596 | ImGui::PopStyleColor(); | ||
| 1597 | } | ||
| 1598 | } | ||
| 1599 | } | ||
| 1600 | ImGui::End(); | ||
| 1601 | } | ||
| 1602 | |||
| 1394 | // --------------------------------------------------------------------------- | 1603 | // --------------------------------------------------------------------------- |
| 1395 | // Entry point | 1604 | // Entry point |
| 1396 | // --------------------------------------------------------------------------- | 1605 | // --------------------------------------------------------------------------- |
| @@ -1457,6 +1666,21 @@ int RunGUI(int argc, char* argv[]) | |||
| 1457 | g_mineRadio = nMineMode; | 1666 | g_mineRadio = nMineMode; |
| 1458 | strncpy(g_participantPool, strParticipantPool.c_str(), sizeof(g_participantPool)-1); | 1667 | strncpy(g_participantPool, strParticipantPool.c_str(), sizeof(g_participantPool)-1); |
| 1459 | 1668 | ||
| 1669 | // Kept for the wizard's "Restart Now": relaunch with the same command line. | ||
| 1670 | g_restartArgc = argc; | ||
| 1671 | g_restartArgv = argv; | ||
| 1672 | |||
| 1673 | // First run on a Berkeley DB wallet with no recorded choice yet: offer to | ||
| 1674 | // convert to SQLite. Never when already on SQLite, once wallet.sqlite exists, | ||
| 1675 | // or once a choice has been recorded in the backend marker. | ||
| 1676 | if (!WalletSQLiteRuntimeActive() && | ||
| 1677 | FileExists((GetAppDir() + "/wallet.dat").c_str()) && | ||
| 1678 | !FileExists((GetAppDir() + "/wallet.sqlite").c_str()) && | ||
| 1679 | ReadWalletBackendMarker().empty()) | ||
| 1680 | { | ||
| 1681 | g_showBackendWizard = true; | ||
| 1682 | } | ||
| 1683 | |||
| 1460 | int frame = 0; | 1684 | int frame = 0; |
| 1461 | while (!glfwWindowShouldClose(window) && !fShutdown) | 1685 | while (!glfwWindowShouldClose(window) && !fShutdown) |
| 1462 | { | 1686 | { |
| @@ -1480,6 +1704,7 @@ int RunGUI(int argc, char* argv[]) | |||
| 1480 | DrawRestorePhraseDialog(); | 1704 | DrawRestorePhraseDialog(); |
| 1481 | DrawDiagnosticsDialog(); | 1705 | DrawDiagnosticsDialog(); |
| 1482 | DrawAboutDialog(); | 1706 | DrawAboutDialog(); |
| 1707 | DrawBackendWizardDialog(); | ||
| 1483 | DrawStatusBar(); | 1708 | DrawStatusBar(); |
| 1484 | 1709 | ||
| 1485 | ImGui::Render(); | 1710 | ImGui::Render(); |