Projects : bitcoin : bitcoin_getblockindex_etc
| 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
| 2 | // Copyright (c) 2009-2012 The Bitcoin developers |
| 3 | // Distributed under the MIT/X11 software license, see the accompanying |
| 4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. |
| 5 | #include "headers.h" |
| 6 | #include "db.h" |
| 7 | #include "bitcoinrpc.h" |
| 8 | #include "net.h" |
| 9 | #include "init.h" |
| 10 | #include "strlcpy.h" |
| 11 | #include <boost/filesystem.hpp> |
| 12 | #include <boost/filesystem/fstream.hpp> |
| 13 | #include <boost/interprocess/sync/file_lock.hpp> |
| 14 | |
| 15 | // v0.5.4 RELEASE (keccak) |
| 16 | |
| 17 | using namespace std; |
| 18 | using namespace boost; |
| 19 | |
| 20 | CWallet* pwalletMain; |
| 21 | |
| 22 | ////////////////////////////////////////////////////////////////////////////// |
| 23 | // |
| 24 | // Shutdown |
| 25 | // |
| 26 | |
| 27 | void ExitTimeout(void* parg) |
| 28 | { |
| 29 | } |
| 30 | |
| 31 | void Shutdown(void* parg) |
| 32 | { |
| 33 | static CCriticalSection cs_Shutdown; |
| 34 | static bool fTaken; |
| 35 | bool fFirstThread = false; |
| 36 | TRY_CRITICAL_BLOCK(cs_Shutdown) |
| 37 | { |
| 38 | fFirstThread = !fTaken; |
| 39 | fTaken = true; |
| 40 | } |
| 41 | static bool fExit; |
| 42 | if (fFirstThread) |
| 43 | { |
| 44 | fShutdown = true; |
| 45 | nTransactionsUpdated++; |
| 46 | DBFlush(false); |
| 47 | StopNode(); |
| 48 | DBFlush(true); |
| 49 | boost::filesystem::remove(GetPidFile()); |
| 50 | UnregisterWallet(pwalletMain); |
| 51 | delete pwalletMain; |
| 52 | CreateThread(ExitTimeout, NULL); |
| 53 | Sleep(50); |
| 54 | printf("Bitcoin exiting\n\n"); |
| 55 | fExit = true; |
| 56 | exit(0); |
| 57 | } |
| 58 | else |
| 59 | { |
| 60 | while (!fExit) |
| 61 | Sleep(500); |
| 62 | Sleep(100); |
| 63 | ExitThread(0); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | void HandleSIGTERM(int) |
| 68 | { |
| 69 | fRequestShutdown = true; |
| 70 | } |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 | ////////////////////////////////////////////////////////////////////////////// |
| 78 | // |
| 79 | // Start |
| 80 | // |
| 81 | |
| 82 | int main(int argc, char* argv[]) |
| 83 | { |
| 84 | bool fRet = false; |
| 85 | fRet = AppInit(argc, argv); |
| 86 | |
| 87 | if (fRet && fDaemon) |
| 88 | return 0; |
| 89 | |
| 90 | return 1; |
| 91 | } |
| 92 | |
| 93 | |
| 94 | bool AppInit(int argc, char* argv[]) |
| 95 | { |
| 96 | bool fRet = false; |
| 97 | try |
| 98 | { |
| 99 | fRet = AppInit2(argc, argv); |
| 100 | } |
| 101 | catch (std::exception& e) { |
| 102 | PrintException(&e, "AppInit()"); |
| 103 | } catch (...) { |
| 104 | PrintException(NULL, "AppInit()"); |
| 105 | } |
| 106 | if (!fRet) |
| 107 | Shutdown(NULL); |
| 108 | return fRet; |
| 109 | } |
| 110 | |
| 111 | bool AppInit2(int argc, char* argv[]) |
| 112 | { |
| 113 | umask(077); |
| 114 | |
| 115 | // Clean shutdown on SIGTERM |
| 116 | struct sigaction sa; |
| 117 | sa.sa_handler = HandleSIGTERM; |
| 118 | sigemptyset(&sa.sa_mask); |
| 119 | sa.sa_flags = 0; |
| 120 | sigaction(SIGTERM, &sa, NULL); |
| 121 | sigaction(SIGINT, &sa, NULL); |
| 122 | sigaction(SIGHUP, &sa, NULL); |
| 123 | |
| 124 | // |
| 125 | // Parameters |
| 126 | // |
| 127 | ParseParameters(argc, argv); |
| 128 | |
| 129 | if (mapArgs.count("-datadir")) |
| 130 | { |
| 131 | if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"]))) |
| 132 | { |
| 133 | filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]); |
| 134 | strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir)); |
| 135 | } |
| 136 | else |
| 137 | { |
| 138 | fprintf(stderr, "Error: Specified directory does not exist\n"); |
| 139 | Shutdown(NULL); |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | |
| 144 | ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir |
| 145 | |
| 146 | if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("--help")) |
| 147 | { |
| 148 | string strUsage = string() + |
| 149 | _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" + |
| 150 | _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + |
| 151 | " bitcoind [options] \t " + "\n" + |
| 152 | " bitcoind [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") + |
| 153 | " bitcoind [options] help \t\t " + _("List commands\n") + |
| 154 | " bitcoind [options] help <command> \t\t " + _("Get help for a command\n") + |
| 155 | _("Options:\n") + |
| 156 | " -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") + |
| 157 | " -pid=<file> \t\t " + _("Specify pid file (default: bitcoind.pid)\n") + |
| 158 | " -gen \t\t " + _("Generate coins\n") + |
| 159 | " -gen=0 \t\t " + _("Don't generate coins\n") + |
| 160 | " -min \t\t " + _("Start minimized\n") + |
| 161 | " -datadir=<dir> \t\t " + _("Specify data directory\n") + |
| 162 | " -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)\n") + |
| 163 | " -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") + |
| 164 | " -port=<port> \t\t " + _("Listen for connections on <port> (default: 8333)\n") + |
| 165 | " -maxconnections=<n>\t " + _("Maintain at most <n> connections to peers (default: 125)\n") + |
| 166 | " -myip=<ip> \t " + _("Set this node's external IP address.\n") + |
| 167 | " -addnode=<ip> \t " + _("Add a node to connect to\n") + |
| 168 | " -connect=<ip> \t\t " + _("Connect only to the specified node\n") + |
| 169 | " -nolisten \t " + _("Don't accept connections from outside\n") + |
| 170 | " -banscore=<n> \t " + _("Threshold for disconnecting misbehaving peers (default: 100)\n") + |
| 171 | " -bantime=<n> \t " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") + |
| 172 | " -permissive Don't ban peers for sending unrecognized message types.\n" + |
| 173 | " -maxreceivebuffer=<n>\t " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)\n") + |
| 174 | " -maxsendbuffer=<n>\t " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)\n") + |
| 175 | " -paytxfee=<amt> Fee to add to transactions you send, in BTC per binary kB\n" + |
| 176 | " -minrelaytxfee=<amt> Minimum fee for accepting transactions into pool, in BTC per binary kB\n" + |
| 177 | " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + |
| 178 | " -debug \t\t " + _("Output extra debugging information\n") + |
| 179 | " -verifyall Forbid the skipping of ECDSA signature verification between checkpoints\n" + |
| 180 | " -setverstring Set a custom version string\n" + |
| 181 | " -setvernum Set a custom version number\n" + |
| 182 | " -highs Normalize ECDSA S-values to 'high' when signing\n" + |
| 183 | " -lows Normalize ECDSA S-values to 'low' when signing (may be necessary as some implementations refuse to relay transactions with high-S signatures)\n" + |
| 184 | " -logtimestamps \t " + _("Prepend debug output with timestamp\n") + |
| 185 | " -printtoconsole \t " + _("Send trace/debug info to console instead of debug.log file\n") + |
| 186 | " -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") + |
| 187 | " -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") + |
| 188 | " -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") + |
| 189 | " -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address\n") + |
| 190 | " -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") + |
| 191 | " -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)\n") + |
| 192 | " -rescan Rescan the block chain for missing wallet transactions\n" + |
| 193 | " -disablesafemode Don't lock certain commands when hazards are detected such as DB corruption or network fork\n" + |
| 194 | " -checkblocks=<n> Check the last <n> blocks in current chain on disk for inconsistencies at startup; 0 to check entire current chain (default: 144)\n" + |
| 195 | " -? This help message\n"; |
| 196 | |
| 197 | // Remove tabs |
| 198 | strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end()); |
| 199 | fprintf(stderr, "%s", strUsage.c_str()); |
| 200 | return false; |
| 201 | } |
| 202 | |
| 203 | fDebug = GetBoolArg("-debug"); |
| 204 | fDaemon = GetBoolArg("-daemon"); |
| 205 | fVerifyAll = GetBoolArg("-verifyall"); |
| 206 | fHighS = GetBoolArg("-highs"); |
| 207 | fLowS = GetBoolArg("-lows"); |
| 208 | fTestSafeMode = GetBoolArg("-testsafemode"); /* undocumented */ |
| 209 | fDisableSafeMode = GetBoolArg("-disablesafemode"); |
| 210 | fPermissive = GetBoolArg("-permissive"); |
| 211 | |
| 212 | if (fHighS && fLowS) |
| 213 | { |
| 214 | printf("Error: '-highs' and '-lows' can not be set at the same time.\n"); |
| 215 | return false; |
| 216 | } |
| 217 | |
| 218 | if (mapArgs.count("-setverstring")) |
| 219 | { |
| 220 | CLIENT_NAME = mapArgs["-setverstring"]; |
| 221 | } |
| 222 | |
| 223 | if (mapArgs.count("-setvernum")) |
| 224 | { |
| 225 | VERSION = atoi(mapArgs["-setvernum"]); |
| 226 | } |
| 227 | |
| 228 | if (fDaemon) |
| 229 | fServer = true; |
| 230 | else |
| 231 | fServer = GetBoolArg("-server"); |
| 232 | |
| 233 | /* force fServer when running without GUI */ |
| 234 | fServer = true; |
| 235 | fPrintToConsole = GetBoolArg("-printtoconsole"); |
| 236 | fPrintToDebugger = GetBoolArg("-printtodebugger"); |
| 237 | fLogTimestamps = GetBoolArg("-logtimestamps"); |
| 238 | |
| 239 | if (mapArgs.count("-minrelaytxfee")) |
| 240 | { |
| 241 | int64 nMinFee = 0; |
| 242 | if (!ParseMoney(mapArgs["-minrelaytxfee"], nMinFee)) |
| 243 | { |
| 244 | fprintf(stderr, "Invalid amount for -minrelaytxfee=<amount>\n"); |
| 245 | return false; |
| 246 | } |
| 247 | SetMinRelayTxFee(nMinFee); |
| 248 | } |
| 249 | |
| 250 | if (mapArgs.count("-checkblocks")) |
| 251 | { |
| 252 | int64 tmp = atoi64(mapArgs["-checkblocks"]); |
| 253 | if (tmp < 0 || tmp >= INT_MAX) |
| 254 | { |
| 255 | fprintf(stderr, "-checkblocks=<n> value out of range\n"); |
| 256 | return false; |
| 257 | } |
| 258 | nCheckBlocks = tmp; |
| 259 | } |
| 260 | |
| 261 | for (int i = 1; i < argc; i++) |
| 262 | if (!IsSwitchChar(argv[i][0])) |
| 263 | fCommandLine = true; |
| 264 | |
| 265 | if (fCommandLine) |
| 266 | { |
| 267 | int ret = CommandLineRPC(argc, argv); |
| 268 | exit(ret); |
| 269 | } |
| 270 | |
| 271 | if (fDaemon) |
| 272 | { |
| 273 | // Daemonize |
| 274 | pid_t pid = fork(); |
| 275 | if (pid < 0) |
| 276 | { |
| 277 | fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); |
| 278 | return false; |
| 279 | } |
| 280 | if (pid > 0) |
| 281 | { |
| 282 | CreatePidFile(GetPidFile(), pid); |
| 283 | return true; |
| 284 | } |
| 285 | |
| 286 | pid_t sid = setsid(); |
| 287 | if (sid < 0) |
| 288 | fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); |
| 289 | } |
| 290 | |
| 291 | if (!fDebug && !pszSetDataDir[0]) |
| 292 | ShrinkDebugFile(); |
| 293 | printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); |
| 294 | printf("Bitcoin version %s\n", FormatFullVersion().c_str()); |
| 295 | printf("Default data directory %s\n", GetDefaultDataDir().c_str()); |
| 296 | |
| 297 | if (GetBoolArg("-loadblockindextest")) |
| 298 | { |
| 299 | CTxDB txdb("r"); |
| 300 | txdb.LoadBlockIndex(); |
| 301 | PrintBlockTree(); |
| 302 | return false; |
| 303 | } |
| 304 | |
| 305 | // Make sure only a single bitcoin process is using the data directory. |
| 306 | string strLockFile = GetDataDir() + "/.lock"; |
| 307 | FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist. |
| 308 | if (file) fclose(file); |
| 309 | static boost::interprocess::file_lock lock(strLockFile.c_str()); |
| 310 | if (!lock.try_lock()) |
| 311 | { |
| 312 | wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin"); |
| 313 | return false; |
| 314 | } |
| 315 | |
| 316 | string strErrors; |
| 317 | |
| 318 | // |
| 319 | // Load data files |
| 320 | // |
| 321 | if (fDaemon) |
| 322 | fprintf(stdout, "bitcoin server starting\n"); |
| 323 | strErrors = ""; |
| 324 | int64 nStart; |
| 325 | |
| 326 | InitMessage(_("Loading addresses...")); |
| 327 | printf("Loading addresses...\n"); |
| 328 | nStart = GetTimeMillis(); |
| 329 | if (!LoadAddresses()) |
| 330 | strErrors += _("Error loading addr.dat \n"); |
| 331 | printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
| 332 | |
| 333 | printf("Loading block index...\n"); |
| 334 | nStart = GetTimeMillis(); |
| 335 | if (!LoadBlockIndex()) |
| 336 | { |
| 337 | fprintf(stderr, "Error loading block index\n"); |
| 338 | return false; // We'd better not proceed to touching the wallet if the block index is bad. |
| 339 | } |
| 340 | printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
| 341 | |
| 342 | InitMessage(_("Loading wallet...")); |
| 343 | printf("Loading wallet...\n"); |
| 344 | nStart = GetTimeMillis(); |
| 345 | bool fFirstRun; |
| 346 | pwalletMain = new CWallet("wallet.dat"); |
| 347 | int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); |
| 348 | if (nLoadWalletRet != DB_LOAD_OK) |
| 349 | { |
| 350 | if (nLoadWalletRet == DB_CORRUPT) |
| 351 | strErrors += _("Error loading wallet.dat: Wallet corrupted \n"); |
| 352 | else if (nLoadWalletRet == DB_TOO_NEW) |
| 353 | strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin \n"); |
| 354 | else if (nLoadWalletRet == DB_NEED_REWRITE) |
| 355 | { |
| 356 | strErrors += _("Wallet needed to be rewritten: restart Bitcoin to complete \n"); |
| 357 | wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR); |
| 358 | return false; |
| 359 | } |
| 360 | else |
| 361 | strErrors += _("Error loading wallet.dat \n"); |
| 362 | } |
| 363 | printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
| 364 | |
| 365 | RegisterWallet(pwalletMain); |
| 366 | |
| 367 | CBlockIndex *pindexRescan = pindexBest; |
| 368 | if (GetBoolArg("-rescan")) |
| 369 | pindexRescan = pindexGenesisBlock; |
| 370 | else |
| 371 | { |
| 372 | CWalletDB walletdb("wallet.dat"); |
| 373 | CBlockLocator locator; |
| 374 | if (walletdb.ReadBestBlock(locator)) |
| 375 | pindexRescan = locator.GetBlockIndex(); |
| 376 | } |
| 377 | if (pindexBest != pindexRescan) |
| 378 | { |
| 379 | InitMessage(_("Rescanning...")); |
| 380 | printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); |
| 381 | nStart = GetTimeMillis(); |
| 382 | pwalletMain->ScanForWalletTransactions(pindexRescan, true); |
| 383 | printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
| 384 | } |
| 385 | |
| 386 | InitMessage(_("Done loading")); |
| 387 | printf("Done loading\n"); |
| 388 | |
| 389 | //// debug print |
| 390 | printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); |
| 391 | printf("nBestHeight = %d\n", nBestHeight); |
| 392 | printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size()); |
| 393 | printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size()); |
| 394 | printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size()); |
| 395 | |
| 396 | if (!strErrors.empty()) |
| 397 | { |
| 398 | wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR); |
| 399 | return false; |
| 400 | } |
| 401 | |
| 402 | // Add wallet transactions that aren't already in a block to mapTransactions |
| 403 | pwalletMain->ReacceptWalletTransactions(); |
| 404 | |
| 405 | // Note: Bitcoin-QT stores several settings in the wallet, so we want |
| 406 | // to load the wallet BEFORE parsing command-line arguments, so |
| 407 | // the command-line/bitcoin.conf settings override GUI setting. |
| 408 | |
| 409 | // |
| 410 | // Parameters |
| 411 | // |
| 412 | if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) |
| 413 | { |
| 414 | PrintBlockTree(); |
| 415 | return false; |
| 416 | } |
| 417 | |
| 418 | if (mapArgs.count("-timeout")) |
| 419 | { |
| 420 | int nNewTimeout = GetArg("-timeout", 5000); |
| 421 | if (nNewTimeout > 0 && nNewTimeout < 600000) |
| 422 | nConnectTimeout = nNewTimeout; |
| 423 | } |
| 424 | |
| 425 | if (mapArgs.count("-printblock")) |
| 426 | { |
| 427 | string strMatch = mapArgs["-printblock"]; |
| 428 | int nFound = 0; |
| 429 | for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) |
| 430 | { |
| 431 | uint256 hash = (*mi).first; |
| 432 | if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0) |
| 433 | { |
| 434 | CBlockIndex* pindex = (*mi).second; |
| 435 | CBlock block; |
| 436 | block.ReadFromDisk(pindex); |
| 437 | block.BuildMerkleTree(); |
| 438 | block.print(); |
| 439 | printf("\n"); |
| 440 | nFound++; |
| 441 | } |
| 442 | } |
| 443 | if (nFound == 0) |
| 444 | printf("No blocks matching %s were found\n", strMatch.c_str()); |
| 445 | return false; |
| 446 | } |
| 447 | |
| 448 | fGenerateBitcoins = GetBoolArg("-gen"); |
| 449 | |
| 450 | if (mapArgs.count("-proxy")) |
| 451 | { |
| 452 | fUseProxy = true; |
| 453 | addrProxy = CAddress(mapArgs["-proxy"]); |
| 454 | if (!addrProxy.IsValid()) |
| 455 | { |
| 456 | wxMessageBox(_("Invalid -proxy address"), "Bitcoin"); |
| 457 | return false; |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | bool fTor = (fUseProxy && addrProxy.port == htons(9050)); |
| 462 | if (fTor) |
| 463 | { |
| 464 | // Use SoftSetArg here so user can override any of these if they wish. |
| 465 | // Note: the GetBoolArg() calls for all of these must happen later. |
| 466 | SoftSetArg("-nolisten", true); |
| 467 | } |
| 468 | |
| 469 | fNoListen = GetBoolArg("-nolisten"); |
| 470 | |
| 471 | // Command-line args override in-wallet settings: |
| 472 | |
| 473 | if (!fNoListen) |
| 474 | { |
| 475 | if (!BindListenPort(strErrors)) |
| 476 | { |
| 477 | wxMessageBox(strErrors, "Bitcoin"); |
| 478 | return false; |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | if (mapArgs.count("-addnode")) |
| 483 | { |
| 484 | BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"]) |
| 485 | { |
| 486 | CAddress addr(strAddr); |
| 487 | addr.nTime = 0; // so it won't relay unless successfully connected |
| 488 | if (addr.IsValid()) |
| 489 | AddAddress(addr); |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | if (mapArgs.count("-paytxfee")) |
| 494 | { |
| 495 | int64 nTransactionFee = 0; |
| 496 | if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) |
| 497 | { |
| 498 | fprintf(stderr, "Invalid amount for -paytxfee=<amount>\n"); |
| 499 | return false; |
| 500 | } |
| 501 | if (nTransactionFee > 0.25 * COIN) |
| 502 | fprintf(stderr, "Warning: -paytxfee is set very high. This is the fee you will pay per kB if you send a transaction.\n"); |
| 503 | SetTransactionFee(nTransactionFee); |
| 504 | } |
| 505 | |
| 506 | // |
| 507 | // Start the node |
| 508 | // |
| 509 | if (!CheckDiskSpace()) |
| 510 | return false; |
| 511 | |
| 512 | RandAddSeedPerfmon(); |
| 513 | |
| 514 | if (!CreateThread(StartNode, NULL)) |
| 515 | wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin"); |
| 516 | |
| 517 | if (fServer) |
| 518 | CreateThread(ThreadRPCServer, NULL); |
| 519 | |
| 520 | while (1) |
| 521 | Sleep(5000); |
| 522 | |
| 523 | return true; |
| 524 | } |