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 | } |