Projects : bitcoin : bitcoin_tx_fee_cleanup
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 | " -? This help message\n"; |
195 | |
196 | // Remove tabs |
197 | strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end()); |
198 | fprintf(stderr, "%s", strUsage.c_str()); |
199 | return false; |
200 | } |
201 | |
202 | fDebug = GetBoolArg("-debug"); |
203 | fDaemon = GetBoolArg("-daemon"); |
204 | fVerifyAll = GetBoolArg("-verifyall"); |
205 | fHighS = GetBoolArg("-highs"); |
206 | fLowS = GetBoolArg("-lows"); |
207 | fTestSafeMode = GetBoolArg("-testsafemode"); /* undocumented */ |
208 | fDisableSafeMode = GetBoolArg("-disablesafemode"); |
209 | fPermissive = GetBoolArg("-permissive"); |
210 | |
211 | if (fHighS && fLowS) |
212 | { |
213 | printf("Error: '-highs' and '-lows' can not be set at the same time.\n"); |
214 | return false; |
215 | } |
216 | |
217 | if (mapArgs.count("-setverstring")) |
218 | { |
219 | CLIENT_NAME = mapArgs["-setverstring"]; |
220 | } |
221 | |
222 | if (mapArgs.count("-setvernum")) |
223 | { |
224 | VERSION = atoi(mapArgs["-setvernum"]); |
225 | } |
226 | |
227 | if (fDaemon) |
228 | fServer = true; |
229 | else |
230 | fServer = GetBoolArg("-server"); |
231 | |
232 | /* force fServer when running without GUI */ |
233 | fServer = true; |
234 | fPrintToConsole = GetBoolArg("-printtoconsole"); |
235 | fPrintToDebugger = GetBoolArg("-printtodebugger"); |
236 | fLogTimestamps = GetBoolArg("-logtimestamps"); |
237 | |
238 | if (mapArgs.count("-minrelaytxfee")) |
239 | { |
240 | int64 nMinFee = 0; |
241 | if (!ParseMoney(mapArgs["-minrelaytxfee"], nMinFee)) |
242 | { |
243 | fprintf(stderr, "Invalid amount for -minrelaytxfee=<amount>\n"); |
244 | return false; |
245 | } |
246 | SetMinRelayTxFee(nMinFee); |
247 | } |
248 | |
249 | for (int i = 1; i < argc; i++) |
250 | if (!IsSwitchChar(argv[i][0])) |
251 | fCommandLine = true; |
252 | |
253 | if (fCommandLine) |
254 | { |
255 | int ret = CommandLineRPC(argc, argv); |
256 | exit(ret); |
257 | } |
258 | |
259 | if (fDaemon) |
260 | { |
261 | // Daemonize |
262 | pid_t pid = fork(); |
263 | if (pid < 0) |
264 | { |
265 | fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); |
266 | return false; |
267 | } |
268 | if (pid > 0) |
269 | { |
270 | CreatePidFile(GetPidFile(), pid); |
271 | return true; |
272 | } |
273 | |
274 | pid_t sid = setsid(); |
275 | if (sid < 0) |
276 | fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); |
277 | } |
278 | |
279 | if (!fDebug && !pszSetDataDir[0]) |
280 | ShrinkDebugFile(); |
281 | printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); |
282 | printf("Bitcoin version %s\n", FormatFullVersion().c_str()); |
283 | printf("Default data directory %s\n", GetDefaultDataDir().c_str()); |
284 | |
285 | if (GetBoolArg("-loadblockindextest")) |
286 | { |
287 | CTxDB txdb("r"); |
288 | txdb.LoadBlockIndex(); |
289 | PrintBlockTree(); |
290 | return false; |
291 | } |
292 | |
293 | // Make sure only a single bitcoin process is using the data directory. |
294 | string strLockFile = GetDataDir() + "/.lock"; |
295 | FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist. |
296 | if (file) fclose(file); |
297 | static boost::interprocess::file_lock lock(strLockFile.c_str()); |
298 | if (!lock.try_lock()) |
299 | { |
300 | wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin"); |
301 | return false; |
302 | } |
303 | |
304 | string strErrors; |
305 | |
306 | // |
307 | // Load data files |
308 | // |
309 | if (fDaemon) |
310 | fprintf(stdout, "bitcoin server starting\n"); |
311 | strErrors = ""; |
312 | int64 nStart; |
313 | |
314 | InitMessage(_("Loading addresses...")); |
315 | printf("Loading addresses...\n"); |
316 | nStart = GetTimeMillis(); |
317 | if (!LoadAddresses()) |
318 | strErrors += _("Error loading addr.dat \n"); |
319 | printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
320 | |
321 | InitMessage(_("Loading block index...")); |
322 | printf("Loading block index...\n"); |
323 | nStart = GetTimeMillis(); |
324 | if (!LoadBlockIndex()) |
325 | strErrors += _("Error loading blkindex.dat \n"); |
326 | printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
327 | |
328 | InitMessage(_("Loading wallet...")); |
329 | printf("Loading wallet...\n"); |
330 | nStart = GetTimeMillis(); |
331 | bool fFirstRun; |
332 | pwalletMain = new CWallet("wallet.dat"); |
333 | int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); |
334 | if (nLoadWalletRet != DB_LOAD_OK) |
335 | { |
336 | if (nLoadWalletRet == DB_CORRUPT) |
337 | strErrors += _("Error loading wallet.dat: Wallet corrupted \n"); |
338 | else if (nLoadWalletRet == DB_TOO_NEW) |
339 | strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin \n"); |
340 | else if (nLoadWalletRet == DB_NEED_REWRITE) |
341 | { |
342 | strErrors += _("Wallet needed to be rewritten: restart Bitcoin to complete \n"); |
343 | wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR); |
344 | return false; |
345 | } |
346 | else |
347 | strErrors += _("Error loading wallet.dat \n"); |
348 | } |
349 | printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
350 | |
351 | RegisterWallet(pwalletMain); |
352 | |
353 | CBlockIndex *pindexRescan = pindexBest; |
354 | if (GetBoolArg("-rescan")) |
355 | pindexRescan = pindexGenesisBlock; |
356 | else |
357 | { |
358 | CWalletDB walletdb("wallet.dat"); |
359 | CBlockLocator locator; |
360 | if (walletdb.ReadBestBlock(locator)) |
361 | pindexRescan = locator.GetBlockIndex(); |
362 | } |
363 | if (pindexBest != pindexRescan) |
364 | { |
365 | InitMessage(_("Rescanning...")); |
366 | printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); |
367 | nStart = GetTimeMillis(); |
368 | pwalletMain->ScanForWalletTransactions(pindexRescan, true); |
369 | printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); |
370 | } |
371 | |
372 | InitMessage(_("Done loading")); |
373 | printf("Done loading\n"); |
374 | |
375 | //// debug print |
376 | printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); |
377 | printf("nBestHeight = %d\n", nBestHeight); |
378 | printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size()); |
379 | printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size()); |
380 | printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size()); |
381 | |
382 | if (!strErrors.empty()) |
383 | { |
384 | wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR); |
385 | return false; |
386 | } |
387 | |
388 | // Add wallet transactions that aren't already in a block to mapTransactions |
389 | pwalletMain->ReacceptWalletTransactions(); |
390 | |
391 | // Note: Bitcoin-QT stores several settings in the wallet, so we want |
392 | // to load the wallet BEFORE parsing command-line arguments, so |
393 | // the command-line/bitcoin.conf settings override GUI setting. |
394 | |
395 | // |
396 | // Parameters |
397 | // |
398 | if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) |
399 | { |
400 | PrintBlockTree(); |
401 | return false; |
402 | } |
403 | |
404 | if (mapArgs.count("-timeout")) |
405 | { |
406 | int nNewTimeout = GetArg("-timeout", 5000); |
407 | if (nNewTimeout > 0 && nNewTimeout < 600000) |
408 | nConnectTimeout = nNewTimeout; |
409 | } |
410 | |
411 | if (mapArgs.count("-printblock")) |
412 | { |
413 | string strMatch = mapArgs["-printblock"]; |
414 | int nFound = 0; |
415 | for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) |
416 | { |
417 | uint256 hash = (*mi).first; |
418 | if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0) |
419 | { |
420 | CBlockIndex* pindex = (*mi).second; |
421 | CBlock block; |
422 | block.ReadFromDisk(pindex); |
423 | block.BuildMerkleTree(); |
424 | block.print(); |
425 | printf("\n"); |
426 | nFound++; |
427 | } |
428 | } |
429 | if (nFound == 0) |
430 | printf("No blocks matching %s were found\n", strMatch.c_str()); |
431 | return false; |
432 | } |
433 | |
434 | fGenerateBitcoins = GetBoolArg("-gen"); |
435 | |
436 | if (mapArgs.count("-proxy")) |
437 | { |
438 | fUseProxy = true; |
439 | addrProxy = CAddress(mapArgs["-proxy"]); |
440 | if (!addrProxy.IsValid()) |
441 | { |
442 | wxMessageBox(_("Invalid -proxy address"), "Bitcoin"); |
443 | return false; |
444 | } |
445 | } |
446 | |
447 | bool fTor = (fUseProxy && addrProxy.port == htons(9050)); |
448 | if (fTor) |
449 | { |
450 | // Use SoftSetArg here so user can override any of these if they wish. |
451 | // Note: the GetBoolArg() calls for all of these must happen later. |
452 | SoftSetArg("-nolisten", true); |
453 | } |
454 | |
455 | fNoListen = GetBoolArg("-nolisten"); |
456 | |
457 | // Command-line args override in-wallet settings: |
458 | |
459 | if (!fNoListen) |
460 | { |
461 | if (!BindListenPort(strErrors)) |
462 | { |
463 | wxMessageBox(strErrors, "Bitcoin"); |
464 | return false; |
465 | } |
466 | } |
467 | |
468 | if (mapArgs.count("-addnode")) |
469 | { |
470 | BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"]) |
471 | { |
472 | CAddress addr(strAddr); |
473 | addr.nTime = 0; // so it won't relay unless successfully connected |
474 | if (addr.IsValid()) |
475 | AddAddress(addr); |
476 | } |
477 | } |
478 | |
479 | if (mapArgs.count("-paytxfee")) |
480 | { |
481 | int64 nTransactionFee = 0; |
482 | if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) |
483 | { |
484 | fprintf(stderr, "Invalid amount for -paytxfee=<amount>\n"); |
485 | return false; |
486 | } |
487 | if (nTransactionFee > 0.25 * COIN) |
488 | fprintf(stderr, "Warning: -paytxfee is set very high. This is the fee you will pay per kB if you send a transaction.\n"); |
489 | SetTransactionFee(nTransactionFee); |
490 | } |
491 | |
492 | // |
493 | // Start the node |
494 | // |
495 | if (!CheckDiskSpace()) |
496 | return false; |
497 | |
498 | RandAddSeedPerfmon(); |
499 | |
500 | if (!CreateThread(StartNode, NULL)) |
501 | wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin"); |
502 | |
503 | if (fServer) |
504 | CreateThread(ThreadRPCServer, NULL); |
505 | |
506 | while (1) |
507 | Sleep(5000); |
508 | |
509 | return true; |
510 | } |