upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/main_gui.cpp
diff options
context:
space:
mode:
authorbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
committerbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
commit5ce650382352c1503f40abf08129ada69402af55 (patch)
tree6a18198901f1e2c4933f1ac53c9365eec512bf63 /src/main_gui.cpp
parentf34113291da7e5e3dc7d2468d4f9c212c05c584b (diff)
public commit
Diffstat (limited to 'src/main_gui.cpp')
-rw-r--r--src/main_gui.cpp657
1 files changed, 657 insertions, 0 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
new file mode 100644
index 0000000..875988f
--- /dev/null
+++ b/src/main_gui.cpp
@@ -0,0 +1,657 @@
1// Bitflash entry point -- starts node threads then runs GUI (or headless).
2
3#include "headers_core.h"
4#include "selftest.h"
5#include "walletcmd.h"
6#include <thread> // hardware_concurrency, to sanity-check /genproclimit
7#ifndef _WIN32
8#include <csignal>
9#endif
10
11// BITFLASH_NO_GUI builds the same entry point without ImGui, GLFW or OpenGL,
12// so the binary does not need libGL present just to start. See headless.cpp.
13#ifndef BITFLASH_NO_GUI
14int RunGUI(int argc, char* argv[]);
15#endif
16
17// Global definitions (were in ui.cpp, now here)
18map<string,string> mapAddressBook;
19bool gPoolServerRunning = false;
20
21static bool arg(int argc, char* argv[], const char* key)
22{
23 for (int i=1;i<argc;i++) { string s=argv[i]; if(s==key||s.substr(0,s.find('='))==key) return true; }
24 return false;
25}
26static string argval(int argc, char* argv[], const char* key)
27{
28 for (int i=1;i<argc;i++) {
29 string s=argv[i]; size_t eq=s.find('=');
30 if(eq!=string::npos && s.substr(0,eq)==key) return s.substr(eq+1);
31 }
32 return "";
33}
34
35static string argval2(int argc, char* argv[], const char* keySlash, const char* keyDash)
36{
37 string v = argval(argc, argv, keySlash);
38 if (!v.empty())
39 return v;
40 return argval(argc, argv, keyDash);
41}
42
43static bool ReadPassphraseArgument(const string& strArg, string& strPassphraseRet, string& strErrorRet)
44{
45 strPassphraseRet.clear();
46 strErrorRet.clear();
47 if (strArg.empty())
48 {
49 AttachTerminal();
50 fprintf(stderr, "Enter wallet passphrase: ");
51 fflush(stderr);
52 char buf[4096];
53 if (!fgets(buf, sizeof(buf), stdin))
54 {
55 strErrorRet = "could not read passphrase from stdin";
56 return false;
57 }
58 strPassphraseRet = buf;
59 }
60 else if (strArg[0] == '@')
61 {
62 string strPath = strArg.substr(1);
63 FILE* pf = fopen(strPath.c_str(), "rb");
64 if (!pf)
65 {
66 strErrorRet = strprintf("could not read passphrase file %s", strPath.c_str());
67 return false;
68 }
69 char buf[4096];
70 if (!fgets(buf, sizeof(buf), pf))
71 {
72 fclose(pf);
73 strErrorRet = strprintf("passphrase file %s is empty", strPath.c_str());
74 return false;
75 }
76 fclose(pf);
77 strPassphraseRet = buf;
78 }
79 else
80 {
81 strErrorRet = "passphrase literals on the command line are unsafe; use the option without a value to read stdin, or use @FILE";
82 return false;
83 }
84
85 while (!strPassphraseRet.empty() &&
86 (strPassphraseRet[strPassphraseRet.size() - 1] == '\n' ||
87 strPassphraseRet[strPassphraseRet.size() - 1] == '\r'))
88 strPassphraseRet.resize(strPassphraseRet.size() - 1);
89 if (strPassphraseRet.empty())
90 {
91 strErrorRet = "empty passphrase";
92 return false;
93 }
94 return true;
95}
96
97// The real printf, not the one util.h remaps to OutputDebugStringF. Help that
98// goes to debug.log is help nobody asked for: `-help` printed a full page into
99// the data directory and returned 0 with an empty terminal, which reads as a
100// command that does nothing. Same reason walletcmd.cpp undefines it.
101#undef printf
102
103static void PrintUsage()
104{
105 printf("Bitflash command-line options\n");
106 printf("\n");
107 printf("General:\n");
108 printf(" /help, -help, --help, /?\n");
109 printf(" /datadir=PATH\n");
110 printf(" /debug\n");
111 printf(" /gen\n");
112 printf(" /nogui or /daemon\n");
113 printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, or wallet-encrypt\n");
114 printf("\n");
115 printf("Mining mode:\n");
116 printf(" /operator\n");
117 printf(" /participant=POOL_BTF_ADDRESS\n");
118 printf(" /solomine\n");
119 printf(" /genproclimit=N (mining threads; 0 or absent = every core but one)\n");
120 printf(" /checkblocks=N (blocks re-verified at startup, default 288, 0 = all)\n");
121 printf("\n");
122 printf("Pool operator announcement:\n");
123 printf(" /poolname=NAME\n");
124 printf(" /poolfee=PCT\n");
125 printf(" /pooldashboard=URL (alias: /pooldash=URL)\n");
126 printf("\n");
127 printf(".btf and rendezvous:\n");
128 printf(" /connectbtf=PEER_BTF_ADDRESS\n");
129 printf(" /rvrelay=HOST:PORT\n");
130 printf(" /announcerelay=HOST:PORT\n");
131 printf("\n");
132 printf("Network:\n");
133 printf(" /port=N (P2P listen port, default 8433)\n");
134 printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n");
135 printf("\n");
136 printf("Wallet:\n");
137 printf(" /backupwallet=FILE (write a wallet.dat that opens on its own,\n");
138 printf(" then exit; run it again after new addresses)\n");
139 printf(" /dumpwallet=FILE (export private keys as text -- readable by\n");
140 printf(" anyone, so guard it like cash)\n");
141 printf(" /importwallet=FILE (load keys from such a file back in)\n");
142 printf(" /encryptwallet[=@FILE] (rewrite wallet.dat with encrypted private keys\n");
143 printf(" and encrypted HD seed, then exit)\n");
144 printf(" /walletpassphrase[=@FILE] (unlock an encrypted wallet for one-shot\n");
145 printf(" commands; without @FILE reads stdin)\n");
146 printf(" /newaddress (print the next receiving address, then exit)\n");
147 printf(" /sendto=ADDRESS,AMOUNT (spend from this wallet, then exit -- the\n");
148 printf(" only way to send without the window)\n");
149 printf(" /newphrase (create a twelve-word recovery phrase for a\n");
150 printf(" wallet that has none, show it once, exit)\n");
151 printf(" /restorephrase=\"WORDS\" (rebuild this wallet from a phrase and scan\n");
152 printf(" the chain for its coins, then exit)\n");
153 printf(" /restoredepth=N (with /restorephrase: derive at least N\n");
154 printf(" addresses before giving up)\n");
155 printf(" /showderived=N (list the first N addresses a phrase\n");
156 printf(" installed in this wallet derives)\n");
157 printf(" /recoveryaudit (show how much spendable balance is\n");
158 printf(" covered by the recovery phrase;\n");
159 printf(" exits 2 when wallet.dat is still needed)\n");
160 printf(" /rescan (walk the chain for coins this wallet owns\n");
161 printf(" but never recorded, then exit)\n");
162 printf("\n");
163 printf("Each option also accepts '-' instead of '/'.\n");
164}
165
166#define printf OutputDebugStringF
167
168static void ParseStartupArguments(int argc, char* argv[])
169{
170 if (arg(argc,argv,"/datadir") || arg(argc,argv,"-datadir"))
171 strSetDataDir = argval2(argc, argv, "/datadir", "-datadir");
172
173 if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug"))
174 fDebug = true;
175
176 if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen"))
177 {
178 fGenerateBitcoins = 1;
179 // Mining mode defaults to MINE_RELAY, and nothing in this parser ever
180 // changed it, so BitcoinMiner() returned immediately at its relay guard
181 // and /gen mined nothing at all. /operator and /participant still set
182 // their own mode below, so only the unqualified case is affected.
183 if (nMineMode == MINE_RELAY)
184 nMineMode = MINE_SOLO;
185 fMineModeFromCommandLine = true;
186 }
187
188 if (arg(argc,argv,"/solomine") || arg(argc,argv,"-solomine"))
189 fSoloMineTest = true;
190
191 string strCheckBlocks = argval2(argc, argv, "/checkblocks", "-checkblocks");
192 if (!strCheckBlocks.empty())
193 nCheckBlocksOnLoad = atoi(strCheckBlocks.c_str());
194
195 // /genproclimit=N -- threads to hash with. 0 or absent means automatic,
196 // which is every core but one. Named after Bitcoin's own option so it reads
197 // familiarly to anyone who has run one of these before.
198 string strProcLimit = argval2(argc, argv, "/genproclimit", "-genproclimit");
199 if (!strProcLimit.empty())
200 {
201 int n = atoi(strProcLimit.c_str());
202 unsigned int nCores = std::thread::hardware_concurrency();
203 if (n < 0)
204 fprintf(stderr, "Ignoring /genproclimit=%s: not a thread count\n",
205 strProcLimit.c_str());
206 else if (nCores > 0 && n > (int)nCores * 4)
207 // Well past diminishing returns, and every thread still costs a
208 // scratchpad. Refuse rather than quietly thrash the machine.
209 fprintf(stderr, "Ignoring /genproclimit=%d: this machine has %u core(s)\n",
210 n, nCores);
211 else
212 nMinerThreads = n; // 0 stays automatic
213 }
214
215 if (arg(argc,argv,"/operator") || arg(argc,argv,"-operator"))
216 {
217 nMineMode = MINE_OPERATOR;
218 fMineModeFromCommandLine = true;
219 }
220
221 if (arg(argc,argv,"/participant") || arg(argc,argv,"-participant"))
222 {
223 nMineMode = MINE_PARTICIPANT;
224 strParticipantPool = argval2(argc, argv, "/participant", "-participant");
225 fMineModeFromCommandLine = true;
226 }
227
228 string poolName = argval2(argc, argv, "/poolname", "-poolname");
229 if (!poolName.empty())
230 strPoolName = poolName;
231
232 string poolDash = argval2(argc, argv, "/pooldashboard", "-pooldashboard");
233 if (poolDash.empty())
234 poolDash = argval2(argc, argv, "/pooldash", "-pooldash");
235 if (!poolDash.empty())
236 strPoolDashboardUrl = poolDash;
237
238 string poolFee = argval2(argc, argv, "/poolfee", "-poolfee");
239 if (!poolFee.empty())
240 dPoolFeePercent = atof(poolFee.c_str());
241
242 string btfConnect = argval2(argc, argv, "/connectbtf", "-connectbtf");
243 if (!btfConnect.empty())
244 strBtfConnect = btfConnect;
245
246 string rvRelay = argval2(argc, argv, "/rvrelay", "-rvrelay");
247 if (!rvRelay.empty())
248 {
249 vBtfMeetingRelays.clear();
250 vBtfMeetingRelays.push_back(rvRelay);
251 }
252
253 string announceRelay = argval2(argc, argv, "/announcerelay", "-announcerelay");
254 if (!announceRelay.empty())
255 strBtfAnnounceRelay = announceRelay;
256
257 // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for
258 // testing the seed path and for private networks that ship no compiled list.
259 for (int i = 1; i < argc; i++)
260 {
261 string s = argv[i];
262 size_t eq = s.find('=');
263 if (eq == string::npos) continue;
264 string key = s.substr(0, eq);
265 if (key != "/btfseed" && key != "-btfseed") continue;
266 string val = s.substr(eq + 1);
267 size_t colon = val.rfind(':');
268 if (colon == string::npos || colon + 1 >= val.size())
269 {
270 fprintf(stderr, "Ignoring %s: expected ADDRESS:ENCHEX\n", s.c_str());
271 continue;
272 }
273 vBtfExtraSeeds.push_back(make_pair(val.substr(0, colon), val.substr(colon + 1)));
274 }
275
276 // net.cpp has described nListenPort as "tunable via /port" since it was
277 // written, but nothing ever read the option, so the port was fixed at 8433
278 // and a second node could not start on a machine already running one.
279 string strPort = argval2(argc, argv, "/port", "-port");
280 if (!strPort.empty())
281 {
282 int nPort = atoi(strPort.c_str());
283 if (nPort <= 0 || nPort > 65535)
284 fprintf(stderr, "Ignoring /port=%s: not a port number\n", strPort.c_str());
285 else
286 {
287 nListenPort = htons((unsigned short)nPort);
288 // Or we would announce a port we never bound.
289 addrLocalHost.port = nListenPort;
290 }
291 }
292}
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.
311static 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
338int main(int argc, char* argv[])
339{
340 if (arg(argc,argv,"/help") || arg(argc,argv,"-help") ||
341 arg(argc,argv,"--help") || arg(argc,argv,"/?"))
342 {
343 // Without this the help prints into nothing. A -mwindows binary starts
344 // with no console, so every one of those printfs went nowhere and the
345 // one command whose entire job is to tell you something told you
346 // nothing at all -- exit code 0, not a byte of output.
347 AttachTerminal();
348 PrintUsage();
349 return 0;
350 }
351
352 ParseStartupArguments(argc, argv);
353
354 string strSelfTest = argval2(argc, argv, "/selftest", "-selftest");
355 if (!strSelfTest.empty())
356 return RunSelfTest(strSelfTest);
357
358 // Berkeley DB reports failure by throwing, and CDB's constructor lets it
359 // through. Nothing on this path caught anything, so an unreadable
360 // blkindex.dat or wallet.dat -- one written by another platform's Berkeley
361 // DB, a truncated file, a version mismatch -- unwound out of main() into
362 // std::terminate and abort(). On Windows that surfaces as
363 // STATUS_STACK_BUFFER_OVERRUN (0xC0000409) inside ucrtbase.dll: no message,
364 // no log line past "Loading wallet...", and a faulting module with nothing
365 // to do with the real problem. Confirmed by stack trace:
366 //
367 // libdb_cxx-6.2.dll -> CDB::CDB(...) -> LoadBlockIndex(...) -> main()
368 //
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
379 string strErrors;
380 printf("Loading block index...\n");
381 try
382 {
383 if (!LoadBlockIndex())
384 {
385 FatalStartupError(fHeadlessStartup, "Cannot load the block index.", "");
386 return 1;
387 }
388 }
389 catch (const std::exception& e)
390 {
391 FatalStartupError(fHeadlessStartup,
392 strprintf("Cannot read the block index: %s", e.what()),
393 "blkindex.dat and blk0001.dat may be from another machine or "
394 "incomplete. Deleting both is safe -- they are re-downloaded -- "
395 "but never delete wallet.dat, which holds your keys.");
396 return 1;
397 }
398
399 printf("Loading wallet...\n");
400 try
401 {
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 }
411
412 // After the block index, so there is a chain to compare the wallet
413 // against, and before anything reports a balance.
414 RescanSpentFlags();
415 }
416 catch (const std::exception& e)
417 {
418 FatalStartupError(fHeadlessStartup,
419 strprintf("Cannot read wallet.dat: %s", e.what()),
420 "The file was left untouched. A wallet.dat written by a "
421 "different platform's Berkeley DB is the usual cause; back it "
422 "up before trying anything else.");
423 return 1;
424 }
425 printf("Height=%d\n", nBestHeight);
426
427 bool fEncryptWallet = arg(argc, argv, "/encryptwallet") || arg(argc, argv, "-encryptwallet");
428 string strEncryptWallet = argval2(argc, argv, "/encryptwallet", "-encryptwallet");
429 if (fEncryptWallet)
430 {
431 string strPassphrase;
432 string strPassphraseError;
433 if (!ReadPassphraseArgument(strEncryptWallet, strPassphrase, strPassphraseError))
434 {
435 fprintf(stderr, "Cannot read encryption passphrase: %s\n", strPassphraseError.c_str());
436 DBFlush(true);
437 return 1;
438 }
439 int nRet = CmdEncryptWallet(strPassphrase);
440 if (nRet != 0)
441 DBFlush(true);
442 return nRet;
443 }
444
445 bool fWalletPassphrase = arg(argc, argv, "/walletpassphrase") || arg(argc, argv, "-walletpassphrase");
446 string strWalletPassphrase = argval2(argc, argv, "/walletpassphrase", "-walletpassphrase");
447 if (fWalletPassphrase)
448 {
449 string strPassphrase;
450 string strUnlockError;
451 if (!ReadPassphraseArgument(strWalletPassphrase, strPassphrase, strUnlockError) ||
452 !UnlockWallet(strPassphrase, strUnlockError))
453 {
454 fprintf(stderr, "Cannot unlock wallet: %s\n", strUnlockError.c_str());
455 DBFlush(true);
456 return 1;
457 }
458 }
459
460 // Before the node opens sockets or touches anything: the wallet is loaded,
461 // which is all a backup needs, and finishing here means the copy is taken
462 // from a quiet directory rather than from under a running node.
463 string strBackup = argval2(argc, argv, "/backupwallet", "-backupwallet");
464 if (!strBackup.empty())
465 {
466 bool fOk = BackupWallet(strBackup);
467 if (fOk)
468 {
469 printf("Backed up to %s\n", strBackup.c_str());
470 printf("This file opens on its own -- it does not need the database/ "
471 "directory beside it.\n");
472 printf("It is a snapshot: coins paid to addresses created after now are "
473 "not in it, so back up again whenever you receive to a new address.\n");
474 }
475 else
476 fprintf(stderr, "Backup failed -- nothing was written.\n");
477 DBFlush(true);
478 return fOk ? 0 : 1;
479 }
480
481 string strDump = argval2(argc, argv, "/dumpwallet", "-dumpwallet");
482 if (!strDump.empty())
483 {
484 bool fOk = DumpWallet(strDump);
485 if (fOk)
486 {
487 printf("Wrote %s\n", strDump.c_str());
488 printf("It holds your private keys as readable text. Anyone with the file "
489 "can spend these coins -- keep it off shared storage and delete it "
490 "once you have it somewhere safe.\n");
491 }
492 else
493 fprintf(stderr, "Export failed -- nothing was written.\n");
494 DBFlush(true);
495 return fOk ? 0 : 1;
496 }
497
498 string strImport = argval2(argc, argv, "/importwallet", "-importwallet");
499 if (!strImport.empty())
500 {
501 int nAdded = 0, nSkipped = 0;
502 bool fOk = ImportWallet(strImport, nAdded, nSkipped);
503 if (fOk)
504 {
505 printf("Imported %d key(s); %d were already here.\n", nAdded, nSkipped);
506 // Importing a key without looking for its coins leaves the user
507 // holding a wallet that says zero about money that is on the
508 // chain. That was the old behaviour and it looks exactly like the
509 // import having failed.
510 if (nAdded > 0)
511 {
512 string strScanError;
513 if (!CanScanWalletTransactions(strScanError))
514 {
515 fprintf(stderr, "Cannot scan for imported coins: %s\n",
516 strScanError.c_str());
517 fprintf(stderr, "The key import was written, but the wallet "
518 "balance was not proven against the chain.\n");
519 DBFlush(true);
520 return 1;
521 }
522 printf("Looking through the chain for coins belonging to the imported key(s)...\n");
523 int nFound = ScanForWalletTransactions(pindexGenesisBlock);
524 printf("Found %d transaction(s). Start the node normally to see the balance.\n", nFound);
525 }
526 }
527 else
528 fprintf(stderr, "Import failed.\n");
529 DBFlush(true);
530 return fOk ? 0 : 1;
531 }
532
533 // /rescan -- walk the chain and pick up anything the wallet's keys own but
534 // the wallet never recorded. Cheap to offer and the only recourse when a
535 // balance is wrong for this reason.
536 string strShow = argval2(argc, argv, "/showderived", "-showderived");
537 if (!strShow.empty())
538 {
539 int nRet = CmdShowDerived(atoi(strShow.c_str()));
540 DBFlush(true);
541 return nRet;
542 }
543
544 if (arg(argc,argv,"/newaddress") || arg(argc,argv,"-newaddress"))
545 {
546 int nRet = CmdNewAddress();
547 DBFlush(true);
548 return nRet;
549 }
550
551 // -sendto -- the counterpart to -newaddress. Without it a headless node can
552 // be paid and can never pay: SendMoney() has been here since 0.1.0 and only
553 // the window ever reached it.
554 string strSendTo = argval2(argc, argv, "/sendto", "-sendto");
555 if (!strSendTo.empty())
556 {
557 int nRet = CmdSendTo(strSendTo);
558 DBFlush(true);
559 return nRet;
560 }
561
562 if (arg(argc,argv,"/recoveryaudit") || arg(argc,argv,"-recoveryaudit"))
563 {
564 int nRet = CmdRecoveryAudit();
565 DBFlush(true);
566 return nRet;
567 }
568
569 if (arg(argc,argv,"/newphrase") || arg(argc,argv,"-newphrase"))
570 {
571 int nRet = CmdNewPhrase();
572 DBFlush(true);
573 return nRet;
574 }
575
576 string strRestore = argval2(argc, argv, "/restorephrase", "-restorephrase");
577 if (!strRestore.empty())
578 {
579 string strDepth = argval2(argc, argv, "/restoredepth", "-restoredepth");
580 int nMinDepth = strDepth.empty() ? 0 : atoi(strDepth.c_str());
581 int nRet = CmdRestorePhrase(strRestore, nMinDepth);
582 DBFlush(true);
583 return nRet;
584 }
585
586 if (arg(argc,argv,"/rescan") || arg(argc,argv,"-rescan"))
587 {
588 string strScanError;
589 if (!CanScanWalletTransactions(strScanError))
590 {
591 fprintf(stderr, "Cannot rescan wallet transactions: %s\n",
592 strScanError.c_str());
593 DBFlush(true);
594 return 1;
595 }
596 printf("Rescanning the chain for this wallet's transactions...\n");
597 int nFound = ScanForWalletTransactions(pindexGenesisBlock);
598 printf("Rescan done: %d transaction(s) added or updated.\n", nFound);
599 DBFlush(true);
600 return 0;
601 }
602
603 if (fGenerateBitcoins && IsWalletLocked())
604 {
605 fprintf(stderr, "Cannot mine while the encrypted wallet is locked. "
606 "Start with /walletpassphrase or /walletpassphrase=@FILE, or disable mining.\n");
607 DBFlush(true);
608 return 1;
609 }
610
611 ReacceptWalletTransactions();
612
613 if (!StartNode(strErrors)) { fprintf(stderr,"StartNode: %s\n",strErrors.c_str()); return 1; }
614
615 if (nMineMode == MINE_OPERATOR) {
616 gPoolServerRunning = true;
617 gPoolRunning = true;
618 if (_beginthread(ThreadRPCServer, 0, NULL) == (uintptr_t)-1)
619 printf("Error: _beginthread(ThreadRPCServer) failed\n");
620 }
621 if (fGenerateBitcoins)
622 StartMinerThreads();
623
624#ifdef BITFLASH_NO_GUI
625 // Nothing else this binary can do; /nogui is accepted and redundant.
626 bool fHeadless = true;
627#else
628 bool fHeadless = arg(argc,argv,"/nogui") || arg(argc,argv,"-nogui") ||
629 arg(argc,argv,"/daemon") || arg(argc,argv,"-daemon");
630#endif
631
632 if (fHeadless) {
633#ifndef _WIN32
634 auto sig=[](int){fShutdown=true;};
635 signal(SIGINT,sig); signal(SIGTERM,sig);
636#endif
637 printf("Running headless. Ctrl-C to stop.\n");
638 while (!fShutdown) Sleep(500);
639 StopNode();
640 // Checkpoints, releases wallet.dat from this directory's Berkeley DB
641 // environment, and closes it. Declared since 2009 and never once
642 // called here, which is why a wallet.dat copied elsewhere would not
643 // open -- issue #40. Not optional.
644 DBFlush(true);
645 return 0;
646 }
647
648#ifdef BITFLASH_NO_GUI
649 return 0; // unreachable: fHeadless is always true in this build
650#else
651 int ret = RunGUI(argc, argv);
652 fShutdown = true;
653 StopNode();
654 DBFlush(true);
655 return ret;
656#endif
657}