diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/db.cpp | 19 | ||||
| -rw-r--r-- | src/db.h | 3 | ||||
| -rw-r--r-- | src/main_gui.cpp | 87 |
3 files changed, 94 insertions, 15 deletions
| @@ -48,6 +48,10 @@ private: | |||
| 48 | 48 | ||
| 49 | static CCriticalSection cs_db; | 49 | static CCriticalSection cs_db; |
| 50 | static bool fDbEnvInit = false; | 50 | static bool fDbEnvInit = false; |
| 51 | |||
| 52 | // Why LoadWallet() refused, in words meant for the person who has to act on it. | ||
| 53 | // Empty unless the reason is one we can name. | ||
| 54 | string strWalletLoadError; | ||
| 51 | DbEnv dbenv(0u); | 55 | DbEnv dbenv(0u); |
| 52 | static map<string, int> mapFileUseCount; | 56 | static map<string, int> mapFileUseCount; |
| 53 | 57 | ||
| @@ -625,6 +629,7 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet) | |||
| 625 | bool fHaveStoredMineMode = false; | 629 | bool fHaveStoredMineMode = false; |
| 626 | bool fHaveStoredHDCoinType = false; | 630 | bool fHaveStoredHDCoinType = false; |
| 627 | vchDefaultKeyRet.clear(); | 631 | vchDefaultKeyRet.clear(); |
| 632 | strWalletLoadError.clear(); | ||
| 628 | 633 | ||
| 629 | // Satoshi's "todo: shouldn't we catch exceptions" sat here since 2009, and | 634 | // Satoshi's "todo: shouldn't we catch exceptions" sat here since 2009, and |
| 630 | // it was not a nicety. Nothing on this path caught anything, so a record | 635 | // it was not a nicety. Nothing on this path caught anything, so a record |
| @@ -779,11 +784,15 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet) | |||
| 779 | ssValue >> nMinVersion; | 784 | ssValue >> nMinVersion; |
| 780 | if (nMinVersion > WALLET_FORMAT_SUPPORTED) | 785 | if (nMinVersion > WALLET_FORMAT_SUPPORTED) |
| 781 | { | 786 | { |
| 782 | printf("LoadWallet: wallet.dat requires wallet format %d, " | 787 | // Said out loud, not only into debug.log: this is the one |
| 783 | "but this build only supports format %d\n", | 788 | // refusal whose whole purpose is to be understood, and the |
| 784 | nMinVersion, WALLET_FORMAT_SUPPORTED); | 789 | // caller puts it in front of the user. |
| 785 | printf("LoadWallet: the file was left untouched. Upgrade " | 790 | strWalletLoadError = strprintf( |
| 786 | "Bitflash before opening this wallet.\n"); | 791 | "This wallet.dat was written by a newer version of Bitflash " |
| 792 | "(wallet format %d; this build understands %d). Upgrade " | ||
| 793 | "Bitflash before opening it.", | ||
| 794 | nMinVersion, WALLET_FORMAT_SUPPORTED); | ||
| 795 | printf("LoadWallet: %s\n", strWalletLoadError.c_str()); | ||
| 787 | return false; | 796 | return false; |
| 788 | } | 797 | } |
| 789 | } | 798 | } |
| @@ -54,6 +54,9 @@ extern void DBFlush(bool fShutdown); | |||
| 54 | // this: the logs hold the plaintext records the old wallet wrote. | 54 | // this: the logs hold the plaintext records the old wallet wrote. |
| 55 | extern void PurgeDbEnvironmentLogs(); | 55 | extern void PurgeDbEnvironmentLogs(); |
| 56 | 56 | ||
| 57 | // Set by LoadWallet() when it refuses for a reason worth telling the user. | ||
| 58 | extern string strWalletLoadError; | ||
| 59 | |||
| 57 | 60 | ||
| 58 | 61 | ||
| 59 | 62 | ||
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index a2577ca..875988f 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -291,6 +291,50 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 291 | } | 291 | } |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | // Report a startup failure somewhere the user will actually see it. | ||
| 295 | // | ||
| 296 | // Every fatal path here wrote to stderr and to printf, and on the platform most | ||
| 297 | // people use, neither reaches anybody. printf is remapped to OutputDebugStringF, | ||
| 298 | // so it lands in debug.log inside the data directory. A -mwindows binary | ||
| 299 | // launched by double-clicking has no stderr at all, and AttachTerminal() cannot | ||
| 300 | // help: it attaches to a *parent* console, which a double-clicked exe does not | ||
| 301 | // have. | ||
| 302 | // | ||
| 303 | // So the program exited silently. Someone whose wallet.dat needs a newer build | ||
| 304 | // -- which is exactly what the wallet format guard was added to tell them -- | ||
| 305 | // double-clicked Bitflash and watched nothing happen. | ||
| 306 | // | ||
| 307 | // The box is deliberately not shown for a headless node: those run under | ||
| 308 | // scheduled tasks and services, where a modal dialog waits forever for a click | ||
| 309 | // nobody is there to make. Headless already has a console when it has one, and | ||
| 310 | // its output goes to stderr and the log as before. | ||
| 311 | static void FatalStartupError(bool fHeadless, const string& strWhat, const string& strDetail) | ||
| 312 | { | ||
| 313 | printf("FATAL: %s\n", strWhat.c_str()); | ||
| 314 | if (!strDetail.empty()) | ||
| 315 | printf("FATAL: %s\n", strDetail.c_str()); | ||
| 316 | |||
| 317 | AttachTerminal(); | ||
| 318 | fprintf(stderr, "%s\n", strWhat.c_str()); | ||
| 319 | if (!strDetail.empty()) | ||
| 320 | fprintf(stderr, "%s\n", strDetail.c_str()); | ||
| 321 | fflush(stderr); | ||
| 322 | |||
| 323 | #ifdef _WIN32 | ||
| 324 | if (!fHeadless && GetConsoleWindow() == NULL) | ||
| 325 | { | ||
| 326 | string strBody = strWhat; | ||
| 327 | if (!strDetail.empty()) | ||
| 328 | strBody += "\n\n" + strDetail; | ||
| 329 | strBody += "\n\nNothing was changed. More detail is in debug.log, " | ||
| 330 | "inside the data directory."; | ||
| 331 | MessageBoxA(NULL, strBody.c_str(), "Bitflash", MB_OK | MB_ICONERROR | MB_SETFOREGROUND); | ||
| 332 | } | ||
| 333 | #else | ||
| 334 | (void)fHeadless; | ||
| 335 | #endif | ||
| 336 | } | ||
| 337 | |||
| 294 | int main(int argc, char* argv[]) | 338 | int main(int argc, char* argv[]) |
| 295 | { | 339 | { |
| 296 | if (arg(argc,argv,"/help") || arg(argc,argv,"-help") || | 340 | if (arg(argc,argv,"/help") || arg(argc,argv,"-help") || |
| @@ -323,25 +367,47 @@ int main(int argc, char* argv[]) | |||
| 323 | // libdb_cxx-6.2.dll -> CDB::CDB(...) -> LoadBlockIndex(...) -> main() | 367 | // libdb_cxx-6.2.dll -> CDB::CDB(...) -> LoadBlockIndex(...) -> main() |
| 324 | // | 368 | // |
| 325 | // The program knew what had gone wrong and threw the reason away. | 369 | // The program knew what had gone wrong and threw the reason away. |
| 370 | // Needed here, long before the headless branch runs, because whether a | ||
| 371 | // startup failure may pop a dialog depends on it. | ||
| 372 | #ifdef BITFLASH_NO_GUI | ||
| 373 | bool fHeadlessStartup = true; | ||
| 374 | #else | ||
| 375 | bool fHeadlessStartup = arg(argc,argv,"/nogui") || arg(argc,argv,"-nogui") || | ||
| 376 | arg(argc,argv,"/daemon") || arg(argc,argv,"-daemon"); | ||
| 377 | #endif | ||
| 378 | |||
| 326 | string strErrors; | 379 | string strErrors; |
| 327 | printf("Loading block index...\n"); | 380 | printf("Loading block index...\n"); |
| 328 | try | 381 | try |
| 329 | { | 382 | { |
| 330 | if (!LoadBlockIndex()) { fprintf(stderr, "LoadBlockIndex failed\n"); return 1; } | 383 | if (!LoadBlockIndex()) |
| 384 | { | ||
| 385 | FatalStartupError(fHeadlessStartup, "Cannot load the block index.", ""); | ||
| 386 | return 1; | ||
| 387 | } | ||
| 331 | } | 388 | } |
| 332 | catch (const std::exception& e) | 389 | catch (const std::exception& e) |
| 333 | { | 390 | { |
| 334 | fprintf(stderr, "Cannot read the block index: %s\n", e.what()); | 391 | FatalStartupError(fHeadlessStartup, |
| 335 | fprintf(stderr, "blkindex.dat and blk0001.dat may be from another machine or " | 392 | strprintf("Cannot read the block index: %s", e.what()), |
| 336 | "incomplete. Deleting both is safe -- they are re-downloaded -- " | 393 | "blkindex.dat and blk0001.dat may be from another machine or " |
| 337 | "but never delete wallet.dat, which holds your keys.\n"); | 394 | "incomplete. Deleting both is safe -- they are re-downloaded -- " |
| 395 | "but never delete wallet.dat, which holds your keys."); | ||
| 338 | return 1; | 396 | return 1; |
| 339 | } | 397 | } |
| 340 | 398 | ||
| 341 | printf("Loading wallet...\n"); | 399 | printf("Loading wallet...\n"); |
| 342 | try | 400 | try |
| 343 | { | 401 | { |
| 344 | if (!LoadWallet()) { fprintf(stderr, "LoadWallet failed\n"); return 1; } | 402 | if (!LoadWallet()) |
| 403 | { | ||
| 404 | // LoadWallet() explains itself into strWalletLoadError when it | ||
| 405 | // knows why -- an unsupported wallet format, for one, which is the | ||
| 406 | // case this whole path exists to make visible. | ||
| 407 | FatalStartupError(fHeadlessStartup, "Cannot open wallet.dat.", | ||
| 408 | strWalletLoadError); | ||
| 409 | return 1; | ||
| 410 | } | ||
| 345 | 411 | ||
| 346 | // After the block index, so there is a chain to compare the wallet | 412 | // After the block index, so there is a chain to compare the wallet |
| 347 | // against, and before anything reports a balance. | 413 | // against, and before anything reports a balance. |
| @@ -349,10 +415,11 @@ int main(int argc, char* argv[]) | |||
| 349 | } | 415 | } |
| 350 | catch (const std::exception& e) | 416 | catch (const std::exception& e) |
| 351 | { | 417 | { |
| 352 | fprintf(stderr, "Cannot read wallet.dat: %s\n", e.what()); | 418 | FatalStartupError(fHeadlessStartup, |
| 353 | fprintf(stderr, "The file was left untouched. A wallet.dat written by a " | 419 | strprintf("Cannot read wallet.dat: %s", e.what()), |
| 354 | "different platform's Berkeley DB is the usual cause; back it " | 420 | "The file was left untouched. A wallet.dat written by a " |
| 355 | "up before trying anything else.\n"); | 421 | "different platform's Berkeley DB is the usual cause; back it " |
| 422 | "up before trying anything else."); | ||
| 356 | return 1; | 423 | return 1; |
| 357 | } | 424 | } |
| 358 | printf("Height=%d\n", nBestHeight); | 425 | printf("Height=%d\n", nBestHeight); |