diff options
Diffstat (limited to 'src/main_gui.cpp')
| -rw-r--r-- | src/main_gui.cpp | 154 |
1 files changed, 150 insertions, 4 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index a561174..2e4eb91 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -111,6 +111,8 @@ static void PrintUsage() | |||
| 111 | printf(" /help, -help, --help, /?\n"); | 111 | printf(" /help, -help, --help, /?\n"); |
| 112 | printf(" /datadir=PATH\n"); | 112 | printf(" /datadir=PATH\n"); |
| 113 | printf(" /debug\n"); | 113 | printf(" /debug\n"); |
| 114 | printf(" /debugrelay (/debug plus per-message relay chatter and block dumps)\n"); | ||
| 115 | printf(" /maxdebugfilesize=N (roll debug.log at N MB, default 1024; 0 = never)\n"); | ||
| 114 | printf(" /gen\n"); | 116 | printf(" /gen\n"); |
| 115 | printf(" /nogui or /daemon\n"); | 117 | printf(" /nogui or /daemon\n"); |
| 116 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-storage-sanity,\n"); | 118 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-storage-sanity,\n"); |
| @@ -123,6 +125,9 @@ static void PrintUsage() | |||
| 123 | printf("Mining mode:\n"); | 125 | printf("Mining mode:\n"); |
| 124 | printf(" /operator\n"); | 126 | printf(" /operator\n"); |
| 125 | printf(" /participant=POOL_BTF_ADDRESS\n"); | 127 | printf(" /participant=POOL_BTF_ADDRESS\n"); |
| 128 | printf(" /payoutaddr=BTF_ADDRESS (participant: pay shares to this address, no wallet needed)\n"); | ||
| 129 | printf(" /payoutfile=FILE (participant: rotate payout addresses from file)\n"); | ||
| 130 | printf(" /hashthreads=N (participant: mining threads, default cores-1)\n"); | ||
| 126 | printf(" /stratumbridge=POOL_BTF_ADDRESS\n"); | 131 | printf(" /stratumbridge=POOL_BTF_ADDRESS\n"); |
| 127 | printf(" /stratumbridgeport=N (default 3333; listen on 127.0.0.1)\n"); | 132 | printf(" /stratumbridgeport=N (default 3333; listen on 127.0.0.1)\n"); |
| 128 | printf(" /solomine\n"); | 133 | printf(" /solomine\n"); |
| @@ -150,6 +155,7 @@ static void PrintUsage() | |||
| 150 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); | 155 | printf(" /socks=HOST:PORT (SOCKS5 proxy for Nostr, .btf relay, and onion dials)\n"); |
| 151 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); | 156 | printf(" /tor[=HOST:PORT] (Tor mode; default SOCKS5 proxy is 127.0.0.1:9050)\n"); |
| 152 | printf(" /managedtor[=PATH] (start Tor, create a hidden service, advertise its onion)\n"); | 157 | printf(" /managedtor[=PATH] (start Tor, create a hidden service, advertise its onion)\n"); |
| 158 | printf(" /automanagedtor (auto-start a bundled Tor if one sits next to the executable)\n"); | ||
| 153 | printf(" /nomanagedtor (disable automatic bundled Tor startup)\n"); | 159 | printf(" /nomanagedtor (disable automatic bundled Tor startup)\n"); |
| 154 | printf(" /oniononly (do not fall back to rendezvous when a .btf onion dial fails)\n"); | 160 | printf(" /oniononly (do not fall back to rendezvous when a .btf onion dial fails)\n"); |
| 155 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); | 161 | printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n"); |
| @@ -195,6 +201,9 @@ static void PrintUsage() | |||
| 195 | printf(" /walletsqlite=FILE (stage-load a SQLite wallet export, then exit)\n"); | 201 | printf(" /walletsqlite=FILE (stage-load a SQLite wallet export, then exit)\n"); |
| 196 | printf(" /walletbackend=sqlite (opt-in: run the node on <datadir>/wallet.sqlite\n"); | 202 | printf(" /walletbackend=sqlite (opt-in: run the node on <datadir>/wallet.sqlite\n"); |
| 197 | printf(" instead of wallet.dat; export one first)\n"); | 203 | printf(" instead of wallet.dat; export one first)\n"); |
| 204 | printf(" /createwallet (headless only: permit creating a new wallet in a\n"); | ||
| 205 | printf(" datadir that has none -- otherwise refused, since\n"); | ||
| 206 | printf(" a missing wallet is usually a mount/backup fault)\n"); | ||
| 198 | printf(" /rescan (walk the chain for coins this wallet owns\n"); | 207 | printf(" /rescan (walk the chain for coins this wallet owns\n"); |
| 199 | printf(" but never recorded, then exit)\n"); | 208 | printf(" but never recorded, then exit)\n"); |
| 200 | printf("\n"); | 209 | printf("\n"); |
| @@ -214,6 +223,54 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 214 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) | 223 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) |
| 215 | fDebug = true; | 224 | fDebug = true; |
| 216 | 225 | ||
| 226 | // /debugrelay -- everything /debug shows, plus the per-message firehose | ||
| 227 | // ("relay" and "nostrdiscovery" categories: sending: tx, Relaying wtx, | ||
| 228 | // raw CBlock dumps, per-peer discovery lines). That traffic was ~90% of | ||
| 229 | // a 13-hour production debug.log (issue #35), so plain /debug leaves it | ||
| 230 | // off; the message text itself is unchanged for anyone grepping it. | ||
| 231 | if (arg(argc,argv,"/debugrelay") || arg(argc,argv,"-debugrelay")) | ||
| 232 | { | ||
| 233 | fDebug = true; | ||
| 234 | fDebugRelay = true; | ||
| 235 | } | ||
| 236 | |||
| 237 | // /maxdebugfilesize=N -- roll debug.log to debug.log.old once it passes | ||
| 238 | // N MB, checked on each write. Default is 1024 (see util.cpp); 0 turns | ||
| 239 | // the check off and leaves rotation entirely to logrotate. | ||
| 240 | string strMaxDebugSize = argval2(argc, argv, "/maxdebugfilesize", "-maxdebugfilesize"); | ||
| 241 | if (!strMaxDebugSize.empty()) | ||
| 242 | { | ||
| 243 | // Parsed with atoi64() before, which is strtoll() with the endptr | ||
| 244 | // thrown away: it returns 0 for anything it cannot read, so | ||
| 245 | // /maxdebugfilesize=1G and =1024MB both came out as 0 -- "never | ||
| 246 | // roll", identical to asking for that on purpose, with nothing said | ||
| 247 | // to the operator. The old code also multiplied without a range | ||
| 248 | // check, so a big enough N wrapped to a negative cap, which the roll | ||
| 249 | // reads as "off" too. Every rejection is now reported and leaves the | ||
| 250 | // default in place; the value is a plain count of MB, no suffix. | ||
| 251 | const char* psz = strMaxDebugSize.c_str(); | ||
| 252 | char* pszEnd = NULL; | ||
| 253 | errno = 0; | ||
| 254 | int64 nMB = strtoll(psz, &pszEnd, 10); | ||
| 255 | // INT64_MAX, without depending on which limits header this tree pulls in. | ||
| 256 | const int64 nMaxMB = (int64)((~(uint64)0) >> 1) / (1024 * 1024); | ||
| 257 | const char* pszWhy = NULL; | ||
| 258 | if (pszEnd == psz) | ||
| 259 | pszWhy = "not a number"; | ||
| 260 | else if (*pszEnd != '\0') | ||
| 261 | pszWhy = "trailing characters -- the value is a count of MB, with no unit suffix"; | ||
| 262 | else if (errno == ERANGE || nMB < 0) | ||
| 263 | pszWhy = "not a size in MB"; | ||
| 264 | else if (nMB > nMaxMB) | ||
| 265 | pszWhy = "larger than a file size can be"; | ||
| 266 | if (pszWhy) | ||
| 267 | fprintf(stderr, "Ignoring /maxdebugfilesize=%s: %s (keeping %lld MB)\n", | ||
| 268 | strMaxDebugSize.c_str(), pszWhy, | ||
| 269 | (long long)(nMaxDebugFileSize / 1024 / 1024)); | ||
| 270 | else | ||
| 271 | nMaxDebugFileSize = nMB * 1024 * 1024; | ||
| 272 | } | ||
| 273 | |||
| 217 | if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen")) | 274 | if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen")) |
| 218 | { | 275 | { |
| 219 | fGenerateBitcoins = 1; | 276 | fGenerateBitcoins = 1; |
| @@ -245,7 +302,7 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 245 | if (!strProcLimit.empty()) | 302 | if (!strProcLimit.empty()) |
| 246 | { | 303 | { |
| 247 | int n = atoi(strProcLimit.c_str()); | 304 | int n = atoi(strProcLimit.c_str()); |
| 248 | unsigned int nCores = std::thread::hardware_concurrency(); | 305 | unsigned int nCores = AvailableCoreCount(); |
| 249 | if (n < 0) | 306 | if (n < 0) |
| 250 | fprintf(stderr, "Ignoring /genproclimit=%s: not a thread count\n", | 307 | fprintf(stderr, "Ignoring /genproclimit=%s: not a thread count\n", |
| 251 | strProcLimit.c_str()); | 308 | strProcLimit.c_str()); |
| @@ -271,6 +328,18 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 271 | fMineModeFromCommandLine = true; | 328 | fMineModeFromCommandLine = true; |
| 272 | } | 329 | } |
| 273 | 330 | ||
| 331 | string payoutAddr = argval2(argc, argv, "/payoutaddr", "-payoutaddr"); | ||
| 332 | if (!payoutAddr.empty()) | ||
| 333 | strPayoutAddress = payoutAddr; | ||
| 334 | |||
| 335 | string payoutFile = argval2(argc, argv, "/payoutfile", "-payoutfile"); | ||
| 336 | if (!payoutFile.empty()) | ||
| 337 | strPayoutFile = payoutFile; | ||
| 338 | |||
| 339 | string hashThreads = argval2(argc, argv, "/hashthreads", "-hashthreads"); | ||
| 340 | if (!hashThreads.empty()) | ||
| 341 | nHashThreads = atoi(hashThreads.c_str()); | ||
| 342 | |||
| 274 | if (arg(argc,argv,"/stratumbridge") || arg(argc,argv,"-stratumbridge")) | 343 | if (arg(argc,argv,"/stratumbridge") || arg(argc,argv,"-stratumbridge")) |
| 275 | { | 344 | { |
| 276 | fStratumBridge = true; | 345 | fStratumBridge = true; |
| @@ -297,6 +366,12 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 297 | if (!poolDash.empty()) | 366 | if (!poolDash.empty()) |
| 298 | strPoolDashboardUrl = poolDash; | 367 | strPoolDashboardUrl = poolDash; |
| 299 | 368 | ||
| 369 | if (arg(argc,argv,"/noannounce") || arg(argc,argv,"-noannounce")) | ||
| 370 | fPoolNoAnnounce = true; | ||
| 371 | |||
| 372 | if (arg(argc,argv,"/poolmineblind") || arg(argc,argv,"-poolmineblind")) | ||
| 373 | fPoolMineBlind = true; | ||
| 374 | |||
| 300 | string poolFee = argval2(argc, argv, "/poolfee", "-poolfee"); | 375 | string poolFee = argval2(argc, argv, "/poolfee", "-poolfee"); |
| 301 | if (!poolFee.empty()) | 376 | if (!poolFee.empty()) |
| 302 | dPoolFeePercent = atof(poolFee.c_str()); | 377 | dPoolFeePercent = atof(poolFee.c_str()); |
| @@ -317,8 +392,20 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 317 | string rvRelay = argval2(argc, argv, "/rvrelay", "-rvrelay"); | 392 | string rvRelay = argval2(argc, argv, "/rvrelay", "-rvrelay"); |
| 318 | if (!rvRelay.empty()) | 393 | if (!rvRelay.empty()) |
| 319 | { | 394 | { |
| 320 | vBtfMeetingRelays.clear(); | 395 | if (!LooksLikeRelay(rvRelay)) |
| 321 | vBtfMeetingRelays.push_back(rvRelay); | 396 | { |
| 397 | // A malformed pin must not replace the seed list: with the pin | ||
| 398 | // set, no discovered relay can ever mask the typo, and the pool | ||
| 399 | // would publish a garbage (or no) meeting node forever. | ||
| 400 | fprintf(stderr, "Ignoring /rvrelay=%s: expected host:port\n", | ||
| 401 | rvRelay.c_str()); | ||
| 402 | } | ||
| 403 | else | ||
| 404 | { | ||
| 405 | vBtfMeetingRelays.clear(); | ||
| 406 | vBtfMeetingRelays.push_back(rvRelay); | ||
| 407 | fBtfRelayPinned = true; | ||
| 408 | } | ||
| 322 | } | 409 | } |
| 323 | 410 | ||
| 324 | // net.cpp has described nListenPort as "tunable via /port" since it was | 411 | // net.cpp has described nListenPort as "tunable via /port" since it was |
| @@ -359,8 +446,16 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 359 | bool fTorMode = arg(argc, argv, "/tor") || arg(argc, argv, "-tor"); | 446 | bool fTorMode = arg(argc, argv, "/tor") || arg(argc, argv, "-tor"); |
| 360 | string socksProxy = argval2(argc, argv, "/socks", "-socks"); | 447 | string socksProxy = argval2(argc, argv, "/socks", "-socks"); |
| 361 | string bundledTorPath; | 448 | string bundledTorPath; |
| 449 | // Managed Tor is opt-in on this fork. Upstream 1.2.19 auto-starts a | ||
| 450 | // bundled tor whenever one sits next to the executable, which silently | ||
| 451 | // moves Nostr/.btf traffic onto Tor, creates a hidden service, and starts | ||
| 452 | // publishing descriptors with meeting_node="rendezvous-pending" on nodes | ||
| 453 | // that never asked for it -- against our pinned-relay posture. The | ||
| 454 | // upstream behavior remains available under the explicit /automanagedtor. | ||
| 362 | bool fAutoManagedTor = !fManagedTor && !fNoManagedTor && !fTorMode && | 455 | bool fAutoManagedTor = !fManagedTor && !fNoManagedTor && !fTorMode && |
| 363 | socksProxy.empty() && BtfBundledTorPath(bundledTorPath); | 456 | socksProxy.empty() && |
| 457 | (arg(argc, argv, "/automanagedtor") || arg(argc, argv, "-automanagedtor")) && | ||
| 458 | BtfBundledTorPath(bundledTorPath); | ||
| 364 | if (fManagedTor || fAutoManagedTor) | 459 | if (fManagedTor || fAutoManagedTor) |
| 365 | { | 460 | { |
| 366 | if (fManagedTor && (fTorMode || !socksProxy.empty())) | 461 | if (fManagedTor && (fTorMode || !socksProxy.empty())) |
| @@ -804,6 +899,32 @@ int main(int argc, char* argv[]) | |||
| 804 | else { fUseSQLite = true; fCreateSQLite = true; } | 899 | else { fUseSQLite = true; fCreateSQLite = true; } |
| 805 | } | 900 | } |
| 806 | 901 | ||
| 902 | // A headless node whose datadir holds no wallet of either kind is | ||
| 903 | // far more often an operations fault -- datadir not mounted, or | ||
| 904 | // wallet.dat caught mid-rename by a backup -- than a first run. | ||
| 905 | // Creating one here is not the harmless default it looks like: | ||
| 906 | // success also writes the backend marker, and from then on | ||
| 907 | // restoring the real wallet.dat no longer takes effect, because the | ||
| 908 | // marker keeps the node on the empty wallet it just made. Under | ||
| 909 | // 1.2.19 the same fault created a wallet.dat that a restore | ||
| 910 | // overwrote, so operators could recover by putting the file back. | ||
| 911 | // Refuse instead, and name the flag that makes it deliberate. | ||
| 912 | if (fCreateSQLite && fHeadlessStartup && | ||
| 913 | !arg(argc, argv, "/createwallet") && !arg(argc, argv, "-createwallet")) | ||
| 914 | { | ||
| 915 | AttachTerminal(); | ||
| 916 | fprintf(stderr, | ||
| 917 | "No wallet found in %s\n" | ||
| 918 | "Refusing to create one. On a headless node an absent wallet is\n" | ||
| 919 | "usually a mount or backup fault, and creating one would record a\n" | ||
| 920 | "backend marker that makes restoring the real wallet a no-op.\n" | ||
| 921 | "Pass -createwallet to start a new one deliberately, or\n" | ||
| 922 | "-walletbackend=bdb to run on a Berkeley DB wallet.dat.\n", | ||
| 923 | GetAppDir().c_str()); | ||
| 924 | fflush(stderr); | ||
| 925 | return 1; | ||
| 926 | } | ||
| 927 | |||
| 807 | if (fUseSQLite) | 928 | if (fUseSQLite) |
| 808 | { | 929 | { |
| 809 | AttachTerminal(); | 930 | AttachTerminal(); |
| @@ -1041,6 +1162,31 @@ int main(int argc, char* argv[]) | |||
| 1041 | 1162 | ||
| 1042 | ReacceptWalletTransactions(); | 1163 | ReacceptWalletTransactions(); |
| 1043 | 1164 | ||
| 1165 | // /dumpaddresses=N:FILE -- generate N fresh wallet keys and write their | ||
| 1166 | // addresses (one per line) to FILE, then exit. Keys stay in this wallet; | ||
| 1167 | // the file alone is enough for a miner elsewhere to rotate payout | ||
| 1168 | // addresses via /payoutfile. (No HD/xpub exists in this wallet format.) | ||
| 1169 | string dumpSpec = argval2(argc, argv, "/dumpaddresses", "-dumpaddresses"); | ||
| 1170 | if (!dumpSpec.empty()) | ||
| 1171 | { | ||
| 1172 | size_t colon = dumpSpec.rfind(':'); | ||
| 1173 | if (colon == string::npos) { fprintf(stderr, "usage: /dumpaddresses=N:FILE\n"); return 1; } | ||
| 1174 | int n = atoi(dumpSpec.substr(0, colon).c_str()); | ||
| 1175 | string file = dumpSpec.substr(colon + 1); | ||
| 1176 | FILE* f = fopen(file.c_str(), "w"); | ||
| 1177 | if (!f) { fprintf(stderr, "cannot open %s\n", file.c_str()); return 1; } | ||
| 1178 | for (int i = 0; i < n; i++) | ||
| 1179 | { | ||
| 1180 | CKey key; | ||
| 1181 | key.MakeNewKey(); | ||
| 1182 | if (!AddKey(key)) { fclose(f); fprintf(stderr, "AddKey failed at %d\n", i); return 1; } | ||
| 1183 | fprintf(f, "%s\n", PubKeyToAddress(key.GetPubKey()).c_str()); | ||
| 1184 | } | ||
| 1185 | fclose(f); | ||
| 1186 | printf("wrote %d fresh wallet addresses to %s\n", n, file.c_str()); | ||
| 1187 | return 0; | ||
| 1188 | } | ||
| 1189 | |||
| 1044 | if (!StartNode(strErrors)) | 1190 | if (!StartNode(strErrors)) |
| 1045 | { | 1191 | { |
| 1046 | fprintf(stderr,"StartNode: %s\n",strErrors.c_str()); | 1192 | fprintf(stderr,"StartNode: %s\n",strErrors.c_str()); |