// Bitflash entry point -- starts node threads then runs GUI (or headless). #include "headers_core.h" #ifndef _WIN32 #include #endif // BITFLASH_NO_GUI builds the same entry point without ImGui, GLFW or OpenGL, // so the binary does not need libGL present just to start. See headless.cpp. #ifndef BITFLASH_NO_GUI int RunGUI(int argc, char* argv[]); #endif // Global definitions (were in ui.cpp, now here) map mapAddressBook; bool gPoolServerRunning = false; static bool arg(int argc, char* argv[], const char* key) { for (int i=1;i= val.size()) { fprintf(stderr, "Ignoring %s: expected ADDRESS:ENCHEX\n", s.c_str()); continue; } vBtfExtraSeeds.push_back(make_pair(val.substr(0, colon), val.substr(colon + 1))); } // net.cpp has described nListenPort as "tunable via /port" since it was // written, but nothing ever read the option, so the port was fixed at 8433 // and a second node could not start on a machine already running one. string strPort = argval2(argc, argv, "/port", "-port"); if (!strPort.empty()) { int nPort = atoi(strPort.c_str()); if (nPort <= 0 || nPort > 65535) fprintf(stderr, "Ignoring /port=%s: not a port number\n", strPort.c_str()); else { nListenPort = htons((unsigned short)nPort); // Or we would announce a port we never bound. addrLocalHost.port = nListenPort; } } } int main(int argc, char* argv[]) { if (arg(argc,argv,"/help") || arg(argc,argv,"-help") || arg(argc,argv,"--help") || arg(argc,argv,"/?")) { PrintUsage(); return 0; } ParseStartupArguments(argc, argv); // Berkeley DB reports failure by throwing, and CDB's constructor lets it // through. Nothing on this path caught anything, so an unreadable // blkindex.dat or wallet.dat -- one written by another platform's Berkeley // DB, a truncated file, a version mismatch -- unwound out of main() into // std::terminate and abort(). On Windows that surfaces as // STATUS_STACK_BUFFER_OVERRUN (0xC0000409) inside ucrtbase.dll: no message, // no log line past "Loading wallet...", and a faulting module with nothing // to do with the real problem. Confirmed by stack trace: // // libdb_cxx-6.2.dll -> CDB::CDB(...) -> LoadBlockIndex(...) -> main() // // The program knew what had gone wrong and threw the reason away. string strErrors; printf("Loading block index...\n"); try { if (!LoadBlockIndex()) { fprintf(stderr, "LoadBlockIndex failed\n"); return 1; } } catch (const std::exception& e) { fprintf(stderr, "Cannot read the block index: %s\n", e.what()); fprintf(stderr, "blkindex.dat and blk0001.dat may be from another machine or " "incomplete. Deleting both is safe -- they are re-downloaded -- " "but never delete wallet.dat, which holds your keys.\n"); return 1; } printf("Loading wallet...\n"); try { if (!LoadWallet()) { fprintf(stderr, "LoadWallet failed\n"); return 1; } } catch (const std::exception& e) { fprintf(stderr, "Cannot read wallet.dat: %s\n", e.what()); fprintf(stderr, "The file was left untouched. A wallet.dat written by a " "different platform's Berkeley DB is the usual cause; back it " "up before trying anything else.\n"); return 1; } printf("Height=%d\n", nBestHeight); // Before the node opens sockets or touches anything: the wallet is loaded, // which is all a backup needs, and finishing here means the copy is taken // from a quiet directory rather than from under a running node. string strBackup = argval2(argc, argv, "/backupwallet", "-backupwallet"); if (!strBackup.empty()) { bool fOk = BackupWallet(strBackup); if (fOk) { printf("Backed up to %s\n", strBackup.c_str()); printf("This file opens on its own -- it does not need the database/ " "directory beside it.\n"); printf("It is a snapshot: coins paid to addresses created after now are " "not in it, so back up again whenever you receive to a new address.\n"); } else fprintf(stderr, "Backup failed -- nothing was written.\n"); DBFlush(true); return fOk ? 0 : 1; } string strDump = argval2(argc, argv, "/dumpwallet", "-dumpwallet"); if (!strDump.empty()) { bool fOk = DumpWallet(strDump); if (fOk) { printf("Wrote %s\n", strDump.c_str()); printf("It holds your private keys as readable text. Anyone with the file " "can spend these coins -- keep it off shared storage and delete it " "once you have it somewhere safe.\n"); } else fprintf(stderr, "Export failed -- nothing was written.\n"); DBFlush(true); return fOk ? 0 : 1; } string strImport = argval2(argc, argv, "/importwallet", "-importwallet"); if (!strImport.empty()) { int nAdded = 0, nSkipped = 0; bool fOk = ImportWallet(strImport, nAdded, nSkipped); if (fOk) printf("Imported %d key(s); %d were already here.\n", nAdded, nSkipped); else fprintf(stderr, "Import failed.\n"); DBFlush(true); return fOk ? 0 : 1; } ReacceptWalletTransactions(); if (!StartNode(strErrors)) { fprintf(stderr,"StartNode: %s\n",strErrors.c_str()); return 1; } if (nMineMode == MINE_OPERATOR) { gPoolServerRunning = true; gPoolRunning = true; if (_beginthread(ThreadRPCServer, 0, NULL) == (uintptr_t)-1) printf("Error: _beginthread(ThreadRPCServer) failed\n"); } if (fGenerateBitcoins) if (_beginthread(ThreadBitcoinMiner, 0, NULL) == (uintptr_t)-1) printf("Error: _beginthread(ThreadBitcoinMiner) failed\n"); #ifdef BITFLASH_NO_GUI // Nothing else this binary can do; /nogui is accepted and redundant. bool fHeadless = true; #else bool fHeadless = arg(argc,argv,"/nogui") || arg(argc,argv,"-nogui") || arg(argc,argv,"/daemon") || arg(argc,argv,"-daemon"); #endif if (fHeadless) { #ifndef _WIN32 auto sig=[](int){fShutdown=true;}; signal(SIGINT,sig); signal(SIGTERM,sig); #endif printf("Running headless. Ctrl-C to stop.\n"); while (!fShutdown) Sleep(500); StopNode(); // Checkpoints, releases wallet.dat from this directory's Berkeley DB // environment, and closes it. Declared since 2009 and never once // called here, which is why a wallet.dat copied elsewhere would not // open -- issue #40. Not optional. DBFlush(true); return 0; } #ifdef BITFLASH_NO_GUI return 0; // unreachable: fHeadless is always true in this build #else int ret = RunGUI(argc, argv); fShutdown = true; StopNode(); DBFlush(true); return ret; #endif }