diff options
| author | bitflash <dev@bitflash.network> | 2026-08-18 16:26:34 -0300 |
|---|---|---|
| committer | bitflash <dev@bitflash.network> | 2026-08-18 16:26:34 -0300 |
| commit | 477d57b9a01102b6f79ad9b10b2dcfd280faa1cb (patch) | |
| tree | c320e5c1f6e486affdf255a1a4ac806a01b9da7c /src/gui.cpp | |
| parent | 3f94ec0649f935d00de49ad7b55026317dc64a27 (diff) | |
gui: offer to convert a Berkeley DB wallet to SQLite on first run
A first-run dialog for an existing wallet.dat with no backend choice yet:
"Convert to SQLite" exports the wallet and records the sqlite marker so
the next start opens it; "Keep Berkeley DB" records that choice so the
offer does not return; "Decide later" leaves no marker and asks again.
wallet.dat is never touched, and the change takes effect on restart --
matching the restart-to-apply model.
The conversion itself is DoConvertWalletToSQLite(), a headless-testable
function the button calls: it reuses the export path (extracted as
ExportActiveWalletToSQLite, shared with -walletsqliteexport, which keeps
its own specific messages), refuses if already on SQLite or if a
wallet.sqlite exists, and writes the marker only after a verified export.
New wallet-convert self-test proves the action end to end: build a
Berkeley DB wallet, convert, and confirm wallet.sqlite + the marker are
written, wallet.dat is left untouched, a second convert refuses, and a
flagless restart opens the converted SQLite wallet with its phrase intact.
All wallet suites pass. The modal itself is thin UI over this tested
action.
Diffstat (limited to 'src/gui.cpp')
| -rw-r--r-- | src/gui.cpp | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/gui.cpp b/src/gui.cpp index 8dcb854..89a7ab6 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -1391,6 +1391,84 @@ static void DrawAboutDialog() | |||
| 1391 | ImGui::End(); | 1391 | ImGui::End(); |
| 1392 | } | 1392 | } |
| 1393 | 1393 | ||
| 1394 | // First-run offer to move a Berkeley DB wallet to the SQLite backend. Only the | ||
| 1395 | // button actions touch anything: "Convert" exports wallet.dat to wallet.sqlite | ||
| 1396 | // and records the backend marker (wallet.dat is left untouched, so a restart | ||
| 1397 | // picks up SQLite while the old file stays as a fallback); "Keep Berkeley DB" | ||
| 1398 | // just records that choice so the offer does not return; "Decide later" leaves | ||
| 1399 | // no marker and asks again next start. | ||
| 1400 | static bool g_showBackendWizard = false; | ||
| 1401 | static std::string g_wizardStatus; | ||
| 1402 | static bool g_wizardConverted = false; | ||
| 1403 | |||
| 1404 | static void DrawBackendWizardDialog() | ||
| 1405 | { | ||
| 1406 | if (!g_showBackendWizard) return; | ||
| 1407 | ImGui::SetNextWindowSize(ImVec2(560.0f, 0.0f), ImGuiCond_Always); | ||
| 1408 | ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), | ||
| 1409 | ImGuiCond_Always, ImVec2(0.5f, 0.5f)); | ||
| 1410 | if (ImGui::Begin("Wallet Storage", &g_showBackendWizard, | ||
| 1411 | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) | ||
| 1412 | { | ||
| 1413 | if (g_wizardConverted) | ||
| 1414 | { | ||
| 1415 | ImGui::TextColored(ImVec4(0.35f, 1.0f, 0.45f, 1.0f), "Converted to SQLite."); | ||
| 1416 | ImGui::TextWrapped("%s", g_wizardStatus.c_str()); | ||
| 1417 | ImGui::Spacing(); | ||
| 1418 | ImGui::TextWrapped( | ||
| 1419 | "Restart Bitflash to start using the SQLite wallet. Your Berkeley " | ||
| 1420 | "DB wallet.dat is kept untouched as a fallback."); | ||
| 1421 | ImGui::Spacing(); | ||
| 1422 | if (ImGui::Button("Close", ImVec2(120.0f, 0.0f))) | ||
| 1423 | g_showBackendWizard = false; | ||
| 1424 | } | ||
| 1425 | else | ||
| 1426 | { | ||
| 1427 | ImGui::TextWrapped( | ||
| 1428 | "Bitflash can store your wallet in a new SQLite format: a single " | ||
| 1429 | "file that is easier to back up and does not depend on the " | ||
| 1430 | "database/ directory beside it."); | ||
| 1431 | ImGui::Spacing(); | ||
| 1432 | ImGui::TextWrapped( | ||
| 1433 | "Your current Berkeley DB wallet (wallet.dat) is kept exactly as it " | ||
| 1434 | "is -- nothing is deleted, and you can go back to it at any time. " | ||
| 1435 | "The change takes effect after you restart."); | ||
| 1436 | ImGui::Spacing(); | ||
| 1437 | if (ImGui::Button("Convert to SQLite", ImVec2(180.0f, 0.0f))) | ||
| 1438 | { | ||
| 1439 | int nCopied = 0; | ||
| 1440 | std::string strError; | ||
| 1441 | if (DoConvertWalletToSQLite(nCopied, strError)) | ||
| 1442 | { | ||
| 1443 | g_wizardStatus = | ||
| 1444 | strprintf("%d record(s) copied to wallet.sqlite.", nCopied); | ||
| 1445 | g_wizardConverted = true; | ||
| 1446 | } | ||
| 1447 | else | ||
| 1448 | g_wizardStatus = "Conversion failed: " + strError; | ||
| 1449 | } | ||
| 1450 | ImGui::SameLine(); | ||
| 1451 | if (ImGui::Button("Keep Berkeley DB", ImVec2(160.0f, 0.0f))) | ||
| 1452 | { | ||
| 1453 | WriteWalletBackendMarker("bdb"); | ||
| 1454 | g_showBackendWizard = false; | ||
| 1455 | } | ||
| 1456 | ImGui::SameLine(); | ||
| 1457 | if (ImGui::Button("Decide later", ImVec2(120.0f, 0.0f))) | ||
| 1458 | g_showBackendWizard = false; | ||
| 1459 | |||
| 1460 | if (!g_wizardStatus.empty()) | ||
| 1461 | { | ||
| 1462 | ImGui::Spacing(); | ||
| 1463 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.45f, 0.35f, 1.0f)); | ||
| 1464 | ImGui::TextWrapped("%s", g_wizardStatus.c_str()); | ||
| 1465 | ImGui::PopStyleColor(); | ||
| 1466 | } | ||
| 1467 | } | ||
| 1468 | } | ||
| 1469 | ImGui::End(); | ||
| 1470 | } | ||
| 1471 | |||
| 1394 | // --------------------------------------------------------------------------- | 1472 | // --------------------------------------------------------------------------- |
| 1395 | // Entry point | 1473 | // Entry point |
| 1396 | // --------------------------------------------------------------------------- | 1474 | // --------------------------------------------------------------------------- |
| @@ -1457,6 +1535,17 @@ int RunGUI(int argc, char* argv[]) | |||
| 1457 | g_mineRadio = nMineMode; | 1535 | g_mineRadio = nMineMode; |
| 1458 | strncpy(g_participantPool, strParticipantPool.c_str(), sizeof(g_participantPool)-1); | 1536 | strncpy(g_participantPool, strParticipantPool.c_str(), sizeof(g_participantPool)-1); |
| 1459 | 1537 | ||
| 1538 | // First run on a Berkeley DB wallet with no recorded choice yet: offer to | ||
| 1539 | // convert to SQLite. Never when already on SQLite, once wallet.sqlite exists, | ||
| 1540 | // or once a choice has been recorded in the backend marker. | ||
| 1541 | if (!WalletSQLiteRuntimeActive() && | ||
| 1542 | FileExists((GetAppDir() + "/wallet.dat").c_str()) && | ||
| 1543 | !FileExists((GetAppDir() + "/wallet.sqlite").c_str()) && | ||
| 1544 | ReadWalletBackendMarker().empty()) | ||
| 1545 | { | ||
| 1546 | g_showBackendWizard = true; | ||
| 1547 | } | ||
| 1548 | |||
| 1460 | int frame = 0; | 1549 | int frame = 0; |
| 1461 | while (!glfwWindowShouldClose(window) && !fShutdown) | 1550 | while (!glfwWindowShouldClose(window) && !fShutdown) |
| 1462 | { | 1551 | { |
| @@ -1480,6 +1569,7 @@ int RunGUI(int argc, char* argv[]) | |||
| 1480 | DrawRestorePhraseDialog(); | 1569 | DrawRestorePhraseDialog(); |
| 1481 | DrawDiagnosticsDialog(); | 1570 | DrawDiagnosticsDialog(); |
| 1482 | DrawAboutDialog(); | 1571 | DrawAboutDialog(); |
| 1572 | DrawBackendWizardDialog(); | ||
| 1483 | DrawStatusBar(); | 1573 | DrawStatusBar(); |
| 1484 | 1574 | ||
| 1485 | ImGui::Render(); | 1575 | ImGui::Render(); |