diff options
Diffstat (limited to 'src/main_gui.cpp')
| -rw-r--r-- | src/main_gui.cpp | 107 |
1 files changed, 105 insertions, 2 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index bee4b95..e941522 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // Bitflash entry point -- starts node threads then runs GUI (or headless). | 1 | // Bitflash entry point -- starts node threads then runs GUI (or headless). |
| 2 | 2 | ||
| 3 | #include "headers_core.h" | 3 | #include "headers_core.h" |
| 4 | #include "proxy.h" | ||
| 4 | #include "selftest.h" | 5 | #include "selftest.h" |
| 5 | #include "walletcmd.h" | 6 | #include "walletcmd.h" |
| 6 | #include <thread> // hardware_concurrency, to sanity-check /genproclimit | 7 | #include <thread> // hardware_concurrency, to sanity-check /genproclimit |
| @@ -110,7 +111,8 @@ static void PrintUsage() | |||
| 110 | printf(" /debug\n"); | 111 | printf(" /debug\n"); |
| 111 | printf(" /gen\n"); | 112 | printf(" /gen\n"); |
| 112 | printf(" /nogui or /daemon\n"); | 113 | printf(" /nogui or /daemon\n"); |
| 113 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, or wallet-encrypt\n"); | 114 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n"); |
| 115 | printf(" net-message, consensus-limits, pool-stratum, parse-money, or socks5-proxy\n"); | ||
| 114 | printf("\n"); | 116 | printf("\n"); |
| 115 | printf("Mining mode:\n"); | 117 | printf("Mining mode:\n"); |
| 116 | printf(" /operator\n"); | 118 | printf(" /operator\n"); |
| @@ -118,6 +120,8 @@ static void PrintUsage() | |||
| 118 | printf(" /payoutaddr=BTF_ADDRESS (participant: pay shares to this address, no wallet needed)\n"); | 120 | printf(" /payoutaddr=BTF_ADDRESS (participant: pay shares to this address, no wallet needed)\n"); |
| 119 | printf(" /payoutfile=FILE (participant: rotate payout addresses from file)\n"); | 121 | printf(" /payoutfile=FILE (participant: rotate payout addresses from file)\n"); |
| 120 | printf(" /hashthreads=N (participant: mining threads, default cores-1)\n"); | 122 | printf(" /hashthreads=N (participant: mining threads, default cores-1)\n"); |
| 123 | printf(" /stratumbridge=POOL_BTF_ADDRESS\n"); | ||
| 124 | printf(" /stratumbridgeport=N (default 3333; listen on 127.0.0.1)\n"); | ||
| 121 | printf(" /solomine\n"); | 125 | printf(" /solomine\n"); |
| 122 | printf(" /genproclimit=N (mining threads; 0 or absent = every core but one)\n"); | 126 | printf(" /genproclimit=N (mining threads; 0 or absent = every core but one)\n"); |
| 123 | printf(" /checkblocks=N (blocks re-verified at startup, default 288, 0 = all)\n"); | 127 | printf(" /checkblocks=N (blocks re-verified at startup, default 288, 0 = all)\n"); |
| @@ -126,6 +130,8 @@ static void PrintUsage() | |||
| 126 | printf(" /poolname=NAME\n"); | 130 | printf(" /poolname=NAME\n"); |
| 127 | printf(" /poolfee=PCT\n"); | 131 | printf(" /poolfee=PCT\n"); |
| 128 | printf(" /pooldashboard=URL (alias: /pooldash=URL)\n"); | 132 | printf(" /pooldashboard=URL (alias: /pooldash=URL)\n"); |
| 133 | printf(" /poolstatusfile=PATH (write pool status JSON for dashboards)\n"); | ||
| 134 | printf(" /poolroundsfile=PATH (write public pool round proofs JSON)\n"); | ||
| 129 | printf("\n"); | 135 | printf("\n"); |
| 130 | printf(".btf and rendezvous:\n"); | 136 | printf(".btf and rendezvous:\n"); |
| 131 | printf(" /connectbtf=PEER_BTF_ADDRESS\n"); | 137 | printf(" /connectbtf=PEER_BTF_ADDRESS\n"); |
| @@ -134,6 +140,8 @@ static void PrintUsage() | |||
| 134 | printf("\n"); | 140 | printf("\n"); |
| 135 | printf("Network:\n"); | 141 | printf("Network:\n"); |
| 136 | printf(" /port=N (P2P listen port, default 8433)\n"); | 142 | printf(" /port=N (P2P listen port, default 8433)\n"); |
| 143 | printf(" /socks=HOST:PORT (SOCKS5 proxy for outbound Nostr and .btf relay dials)\n"); | ||
| 144 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); | ||
| 137 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); | 145 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); |
| 138 | printf("\n"); | 146 | printf("\n"); |
| 139 | printf("Wallet:\n"); | 147 | printf("Wallet:\n"); |
| @@ -240,6 +248,22 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 240 | if (!hashThreads.empty()) | 248 | if (!hashThreads.empty()) |
| 241 | nHashThreads = atoi(hashThreads.c_str()); | 249 | nHashThreads = atoi(hashThreads.c_str()); |
| 242 | 250 | ||
| 251 | if (arg(argc,argv,"/stratumbridge") || arg(argc,argv,"-stratumbridge")) | ||
| 252 | { | ||
| 253 | fStratumBridge = true; | ||
| 254 | string bridgePool = argval2(argc, argv, "/stratumbridge", "-stratumbridge"); | ||
| 255 | if (!bridgePool.empty()) | ||
| 256 | strParticipantPool = bridgePool; | ||
| 257 | } | ||
| 258 | |||
| 259 | string bridgePort = argval2(argc, argv, "/stratumbridgeport", "-stratumbridgeport"); | ||
| 260 | if (!bridgePort.empty()) | ||
| 261 | { | ||
| 262 | int nPort = atoi(bridgePort.c_str()); | ||
| 263 | if (nPort > 0 && nPort <= 65535) | ||
| 264 | nStratumBridgePort = nPort; | ||
| 265 | } | ||
| 266 | |||
| 243 | string poolName = argval2(argc, argv, "/poolname", "-poolname"); | 267 | string poolName = argval2(argc, argv, "/poolname", "-poolname"); |
| 244 | if (!poolName.empty()) | 268 | if (!poolName.empty()) |
| 245 | strPoolName = poolName; | 269 | strPoolName = poolName; |
| @@ -260,6 +284,14 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 260 | if (!poolFee.empty()) | 284 | if (!poolFee.empty()) |
| 261 | dPoolFeePercent = atof(poolFee.c_str()); | 285 | dPoolFeePercent = atof(poolFee.c_str()); |
| 262 | 286 | ||
| 287 | string poolStatusFile = argval2(argc, argv, "/poolstatusfile", "-poolstatusfile"); | ||
| 288 | if (!poolStatusFile.empty()) | ||
| 289 | strPoolStatusFile = poolStatusFile; | ||
| 290 | |||
| 291 | string poolRoundsFile = argval2(argc, argv, "/poolroundsfile", "-poolroundsfile"); | ||
| 292 | if (!poolRoundsFile.empty()) | ||
| 293 | strPoolRoundsFile = poolRoundsFile; | ||
| 294 | |||
| 263 | string btfConnect = argval2(argc, argv, "/connectbtf", "-connectbtf"); | 295 | string btfConnect = argval2(argc, argv, "/connectbtf", "-connectbtf"); |
| 264 | if (!btfConnect.empty()) | 296 | if (!btfConnect.empty()) |
| 265 | strBtfConnect = btfConnect; | 297 | strBtfConnect = btfConnect; |
| @@ -287,6 +319,36 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 287 | if (!announceRelay.empty()) | 319 | if (!announceRelay.empty()) |
| 288 | strBtfAnnounceRelay = announceRelay; | 320 | strBtfAnnounceRelay = announceRelay; |
| 289 | 321 | ||
| 322 | bool fTorMode = arg(argc, argv, "/tor") || arg(argc, argv, "-tor"); | ||
| 323 | if (fTorMode) | ||
| 324 | { | ||
| 325 | string socksProxy = argval2(argc, argv, "/socks", "-socks"); | ||
| 326 | if (!socksProxy.empty()) | ||
| 327 | fprintf(stderr, "Warning: /tor takes precedence over /socks=%s\n", | ||
| 328 | socksProxy.c_str()); | ||
| 329 | |||
| 330 | string torProxy = argval2(argc, argv, "/tor", "-tor"); | ||
| 331 | string err; | ||
| 332 | if (!BtfEnableTorProxy(torProxy, err)) | ||
| 333 | fprintf(stderr, "Ignoring /tor=%s: %s\n", torProxy.c_str(), err.c_str()); | ||
| 334 | else | ||
| 335 | fprintf(stderr, "Tor mode enabled through SOCKS5 proxy %s\n", | ||
| 336 | BtfSocks5ProxyName().c_str()); | ||
| 337 | } | ||
| 338 | else | ||
| 339 | { | ||
| 340 | string socksProxy = argval2(argc, argv, "/socks", "-socks"); | ||
| 341 | if (!socksProxy.empty()) | ||
| 342 | { | ||
| 343 | string err; | ||
| 344 | if (!BtfSetSocks5Proxy(socksProxy, err)) | ||
| 345 | fprintf(stderr, "Ignoring /socks=%s: %s\n", socksProxy.c_str(), err.c_str()); | ||
| 346 | else | ||
| 347 | fprintf(stderr, "SOCKS5 proxy enabled for outbound discovery/relay dials: %s\n", | ||
| 348 | BtfSocks5ProxyName().c_str()); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 290 | // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for | 352 | // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for |
| 291 | // testing the seed path and for private networks that ship no compiled list. | 353 | // testing the seed path and for private networks that ship no compiled list. |
| 292 | for (int i = 1; i < argc; i++) | 354 | for (int i = 1; i < argc; i++) |
| @@ -368,6 +430,36 @@ static void FatalStartupError(bool fHeadless, const string& strWhat, const strin | |||
| 368 | #endif | 430 | #endif |
| 369 | } | 431 | } |
| 370 | 432 | ||
| 433 | #ifdef _WIN32 | ||
| 434 | // Windows equivalent of the SIGINT/SIGTERM handler the headless loop installs on | ||
| 435 | // POSIX. Without it a headless node on Windows had no way to reach the clean | ||
| 436 | // StopNode()+DBFlush() path: Ctrl-C, closing the console window, a service stop | ||
| 437 | // and OS shutdown all killed it mid-write, and a wallet.dat left unflushed by | ||
| 438 | // Berkeley DB will not reopen. For CLOSE/LOGOFF/SHUTDOWN the OS terminates us | ||
| 439 | // shortly after the handler returns, so we set fShutdown and then block until the | ||
| 440 | // main loop signals the flush is done -- returning any sooner throws the flush | ||
| 441 | // away, which is the whole bug. (A `taskkill /F` is still an uncatchable hard | ||
| 442 | // kill; nothing can help there, and nothing should pretend to.) | ||
| 443 | static volatile bool g_fHeadlessShutdownDone = false; | ||
| 444 | static BOOL WINAPI HeadlessConsoleCtrlHandler(DWORD dwCtrlType) | ||
| 445 | { | ||
| 446 | switch (dwCtrlType) | ||
| 447 | { | ||
| 448 | case CTRL_C_EVENT: | ||
| 449 | case CTRL_BREAK_EVENT: | ||
| 450 | case CTRL_CLOSE_EVENT: | ||
| 451 | case CTRL_LOGOFF_EVENT: | ||
| 452 | case CTRL_SHUTDOWN_EVENT: | ||
| 453 | fShutdown = true; | ||
| 454 | while (!g_fHeadlessShutdownDone) | ||
| 455 | Sleep(50); | ||
| 456 | return TRUE; | ||
| 457 | default: | ||
| 458 | return FALSE; | ||
| 459 | } | ||
| 460 | } | ||
| 461 | #endif | ||
| 462 | |||
| 371 | int main(int argc, char* argv[]) | 463 | int main(int argc, char* argv[]) |
| 372 | { | 464 | { |
| 373 | if (arg(argc,argv,"/help") || arg(argc,argv,"-help") || | 465 | if (arg(argc,argv,"/help") || arg(argc,argv,"-help") || |
| @@ -676,6 +768,10 @@ int main(int argc, char* argv[]) | |||
| 676 | if (_beginthread(ThreadRPCServer, 0, NULL) == (uintptr_t)-1) | 768 | if (_beginthread(ThreadRPCServer, 0, NULL) == (uintptr_t)-1) |
| 677 | printf("Error: _beginthread(ThreadRPCServer) failed\n"); | 769 | printf("Error: _beginthread(ThreadRPCServer) failed\n"); |
| 678 | } | 770 | } |
| 771 | if (fStratumBridge) { | ||
| 772 | if (_beginthread(ThreadStratumBridge, 0, NULL) == (uintptr_t)-1) | ||
| 773 | printf("Error: _beginthread(ThreadStratumBridge) failed\n"); | ||
| 774 | } | ||
| 679 | if (fGenerateBitcoins) | 775 | if (fGenerateBitcoins) |
| 680 | StartMinerThreads(); | 776 | StartMinerThreads(); |
| 681 | 777 | ||
| @@ -688,7 +784,9 @@ int main(int argc, char* argv[]) | |||
| 688 | #endif | 784 | #endif |
| 689 | 785 | ||
| 690 | if (fHeadless) { | 786 | if (fHeadless) { |
| 691 | #ifndef _WIN32 | 787 | #ifdef _WIN32 |
| 788 | SetConsoleCtrlHandler(HeadlessConsoleCtrlHandler, TRUE); | ||
| 789 | #else | ||
| 692 | auto sig=[](int){fShutdown=true;}; | 790 | auto sig=[](int){fShutdown=true;}; |
| 693 | signal(SIGINT,sig); signal(SIGTERM,sig); | 791 | signal(SIGINT,sig); signal(SIGTERM,sig); |
| 694 | #endif | 792 | #endif |
| @@ -700,6 +798,11 @@ int main(int argc, char* argv[]) | |||
| 700 | // called here, which is why a wallet.dat copied elsewhere would not | 798 | // called here, which is why a wallet.dat copied elsewhere would not |
| 701 | // open -- issue #40. Not optional. | 799 | // open -- issue #40. Not optional. |
| 702 | DBFlush(true); | 800 | DBFlush(true); |
| 801 | #ifdef _WIN32 | ||
| 802 | // wallet.dat is safely flushed and closed now; let a pending console | ||
| 803 | // control handler (CLOSE/LOGOFF/SHUTDOWN) return so the OS can finish. | ||
| 804 | g_fHeadlessShutdownDone = true; | ||
| 805 | #endif | ||
| 703 | return 0; | 806 | return 0; |
| 704 | } | 807 | } |
| 705 | 808 | ||