block index checking on load, extra redundant checks, misc refactoring
[novacoin.git] / init.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 #include "headers.h"\r
6 \r
7 \r
8 \r
9 \r
10 \r
11 \r
12 \r
13 \r
14 //////////////////////////////////////////////////////////////////////////////\r
15 //\r
16 // Shutdown\r
17 //\r
18 \r
19 void ExitTimeout(void* parg)\r
20 {\r
21 #ifdef __WXMSW__\r
22     Sleep(5000);\r
23     ExitProcess(0);\r
24 #endif\r
25 }\r
26 \r
27 void Shutdown(void* parg)\r
28 {\r
29     static CCriticalSection cs_Shutdown;\r
30     static bool fTaken;\r
31     bool fFirstThread;\r
32     CRITICAL_BLOCK(cs_Shutdown)\r
33     {\r
34         fFirstThread = !fTaken;\r
35         fTaken = true;\r
36     }\r
37     static bool fExit;\r
38     if (fFirstThread)\r
39     {\r
40         fShutdown = true;\r
41         nTransactionsUpdated++;\r
42         DBFlush(false);\r
43         StopNode();\r
44         DBFlush(true);\r
45         CreateThread(ExitTimeout, NULL);\r
46         Sleep(50);\r
47         printf("Bitcoin exiting\n\n");\r
48         fExit = true;\r
49         exit(0);\r
50     }\r
51     else\r
52     {\r
53         while (!fExit)\r
54             Sleep(500);\r
55         Sleep(100);\r
56         ExitThread(0);\r
57     }\r
58 }\r
59 \r
60 \r
61 \r
62 \r
63 \r
64 \r
65 //////////////////////////////////////////////////////////////////////////////\r
66 //\r
67 // Start\r
68 //\r
69 \r
70 #ifndef GUI\r
71 int main(int argc, char* argv[])\r
72 {\r
73     for (int i = 1; i < argc; i++)\r
74         if (!IsSwitchChar(argv[i][0]))\r
75             fCommandLine = true;\r
76     fDaemon = !fCommandLine;\r
77 \r
78 #ifdef __WXGTK__\r
79     if (!fCommandLine)\r
80     {\r
81         // Daemonize\r
82         pid_t pid = fork();\r
83         if (pid < 0)\r
84         {\r
85             fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);\r
86             return 1;\r
87         }\r
88         if (pid > 0)\r
89             pthread_exit((void*)0);\r
90     }\r
91 #endif\r
92 \r
93     if (!AppInit(argc, argv))\r
94         return 1;\r
95 \r
96     while (!fShutdown)\r
97         Sleep(1000000);\r
98     return 0;\r
99 }\r
100 #endif\r
101 \r
102 bool AppInit(int argc, char* argv[])\r
103 {\r
104     bool fRet = false;\r
105     try\r
106     {\r
107         fRet = AppInit2(argc, argv);\r
108     }\r
109     catch (std::exception& e) {\r
110         PrintException(&e, "AppInit()");\r
111     } catch (...) {\r
112         PrintException(NULL, "AppInit()");\r
113     }\r
114     if (!fRet)\r
115         Shutdown(NULL);\r
116     return fRet;\r
117 }\r
118 \r
119 bool AppInit2(int argc, char* argv[])\r
120 {\r
121 #ifdef _MSC_VER\r
122     // Turn off microsoft heap dump noise\r
123     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);\r
124     _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));\r
125 #endif\r
126 #if _MSC_VER >= 1400\r
127     // Disable confusing "helpful" text message on abort, ctrl-c\r
128     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\r
129 #endif\r
130 #ifndef __WXMSW__\r
131     umask(077);\r
132 #endif\r
133 \r
134     //\r
135     // Parameters\r
136     //\r
137     ParseParameters(argc, argv);\r
138 \r
139     if (mapArgs.count("-datadir"))\r
140     {\r
141         filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);\r
142         strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));\r
143     }\r
144 \r
145     ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir\r
146 \r
147     if (mapArgs.count("-?") || mapArgs.count("--help"))\r
148     {\r
149         string strUsage = string() +\r
150           _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +\r
151             "  bitcoin [options]                   \t  " + "\n" +\r
152             "  bitcoin [options] <command> [params]\t  " + _("Send command to -server or bitcoind\n") +\r
153             "  bitcoin [options] help              \t\t  " + _("List commands\n") +\r
154             "  bitcoin [options] help <command>    \t\t  " + _("Get help for a command\n") +\r
155           _("Options:\n") +\r
156             "  -conf=<file>    \t  " + _("Specify configuration file (default: bitcoin.conf)\n") +\r
157             "  -gen            \t  " + _("Generate coins\n") +\r
158             "  -gen=0          \t  " + _("Don't generate coins\n") +\r
159             "  -min            \t  " + _("Start minimized\n") +\r
160             "  -datadir=<dir>  \t  " + _("Specify data directory\n") +\r
161             "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +\r
162             "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +\r
163             "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +\r
164             "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +\r
165             "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +\r
166             "  -?              \t  " + _("This help message\n");\r
167 \r
168 #if defined(__WXMSW__) && defined(GUI)\r
169         // Tabs make the columns line up in the message box\r
170         wxMessageBox(strUsage, "Bitcoin", wxOK);\r
171 #else\r
172         // Remove tabs\r
173         strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());\r
174         fprintf(stderr, "%s", strUsage.c_str());\r
175 #endif\r
176         return false;\r
177     }\r
178 \r
179     if (mapArgs.count("-debug"))\r
180         fDebug = true;\r
181 \r
182     if (mapArgs.count("-printtodebugger"))\r
183         fPrintToDebugger = true;\r
184 \r
185     if (fCommandLine)\r
186     {\r
187         int ret = CommandLineRPC(argc, argv);\r
188         exit(ret);\r
189     }\r
190 \r
191     if (!fDebug && !pszSetDataDir[0])\r
192         ShrinkDebugFile();\r
193     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");\r
194     printf("Bitcoin version %d.%d.%d%s beta\n", VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer);\r
195 #ifdef GUI\r
196     printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());\r
197     printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());\r
198     printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());\r
199 #endif\r
200     printf("Default data directory %s\n", GetDefaultDataDir().c_str());\r
201 \r
202     if (mapArgs.count("-loadblockindextest"))\r
203     {\r
204         CTxDB txdb("r");\r
205         txdb.LoadBlockIndex();\r
206         PrintBlockTree();\r
207         return false;\r
208     }\r
209 \r
210     //\r
211     // Limit to single instance per user\r
212     // Required to protect the database files if we're going to keep deleting log.*\r
213     //\r
214 #if defined(__WXMSW__) && defined(GUI)\r
215     // todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file\r
216     //  maybe should go by whether successfully bind port 8333 instead\r
217     wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");\r
218     for (int i = 0; i < strMutexName.size(); i++)\r
219         if (!isalnum(strMutexName[i]))\r
220             strMutexName[i] = '.';\r
221     wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
222     if (psingleinstancechecker->IsAnotherRunning())\r
223     {\r
224         printf("Existing instance found\n");\r
225         unsigned int nStart = GetTime();\r
226         loop\r
227         {\r
228             // TODO: find out how to do this in Linux, or replace with wxWidgets commands\r
229             // Show the previous instance and exit\r
230             HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");\r
231             if (hwndPrev)\r
232             {\r
233                 if (IsIconic(hwndPrev))\r
234                     ShowWindow(hwndPrev, SW_RESTORE);\r
235                 SetForegroundWindow(hwndPrev);\r
236                 return false;\r
237             }\r
238 \r
239             if (GetTime() > nStart + 60)\r
240                 return false;\r
241 \r
242             // Resume this instance if the other exits\r
243             delete psingleinstancechecker;\r
244             Sleep(1000);\r
245             psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
246             if (!psingleinstancechecker->IsAnotherRunning())\r
247                 break;\r
248         }\r
249     }\r
250 #endif\r
251 \r
252     // Bind to the port early so we can tell if another instance is already running.\r
253     // This is a backup to wxSingleInstanceChecker, which doesn't work on Linux.\r
254     string strErrors;\r
255     if (!BindListenPort(strErrors))\r
256     {\r
257         wxMessageBox(strErrors, "Bitcoin");\r
258         return false;\r
259     }\r
260 \r
261     //\r
262     // Load data files\r
263     //\r
264     if (fDaemon)\r
265         fprintf(stdout, "bitcoin server starting\n");\r
266     strErrors = "";\r
267     int64 nStart;\r
268 \r
269     printf("Loading addresses...\n");\r
270     nStart = GetTimeMillis();\r
271     if (!LoadAddresses())\r
272         strErrors += _("Error loading addr.dat      \n");\r
273     printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
274 \r
275     printf("Loading block index...\n");\r
276     nStart = GetTimeMillis();\r
277     if (!LoadBlockIndex())\r
278         strErrors += _("Error loading blkindex.dat      \n");\r
279     printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
280 \r
281     printf("Loading wallet...\n");\r
282     nStart = GetTimeMillis();\r
283     bool fFirstRun;\r
284     if (!LoadWallet(fFirstRun))\r
285         strErrors += _("Error loading wallet.dat      \n");\r
286     printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
287 \r
288     printf("Done loading\n");\r
289 \r
290         //// debug print\r
291         printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());\r
292         printf("nBestHeight = %d\n",            nBestHeight);\r
293         printf("mapKeys.size() = %d\n",         mapKeys.size());\r
294         printf("mapPubKeys.size() = %d\n",      mapPubKeys.size());\r
295         printf("mapWallet.size() = %d\n",       mapWallet.size());\r
296         printf("mapAddressBook.size() = %d\n",  mapAddressBook.size());\r
297 \r
298     if (!strErrors.empty())\r
299     {\r
300         wxMessageBox(strErrors, "Bitcoin");\r
301         return false;\r
302     }\r
303 \r
304     // Add wallet transactions that aren't already in a block to mapTransactions\r
305     ReacceptWalletTransactions();\r
306 \r
307     //\r
308     // Parameters\r
309     //\r
310     if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))\r
311     {\r
312         PrintBlockTree();\r
313         return false;\r
314     }\r
315 \r
316     if (mapArgs.count("-printblock"))\r
317     {\r
318         string strMatch = mapArgs["-printblock"];\r
319         int nFound = 0;\r
320         for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)\r
321         {\r
322             uint256 hash = (*mi).first;\r
323             if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)\r
324             {\r
325                 CBlockIndex* pindex = (*mi).second;\r
326                 CBlock block;\r
327                 block.ReadFromDisk(pindex);\r
328                 block.BuildMerkleTree();\r
329                 block.print();\r
330                 printf("\n");\r
331                 nFound++;\r
332             }\r
333         }\r
334         if (nFound == 0)\r
335             printf("No blocks matching %s were found\n", strMatch.c_str());\r
336         return false;\r
337     }\r
338 \r
339     if (mapArgs.count("-gen"))\r
340     {\r
341         if (mapArgs["-gen"].empty())\r
342             fGenerateBitcoins = true;\r
343         else\r
344             fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);\r
345     }\r
346 \r
347     if (mapArgs.count("-proxy"))\r
348     {\r
349         fUseProxy = true;\r
350         addrProxy = CAddress(mapArgs["-proxy"]);\r
351         if (!addrProxy.IsValid())\r
352         {\r
353             wxMessageBox(_("Invalid -proxy address"), "Bitcoin");\r
354             return false;\r
355         }\r
356     }\r
357 \r
358     if (mapArgs.count("-addnode"))\r
359     {\r
360         foreach(string strAddr, mapMultiArgs["-addnode"])\r
361         {\r
362             CAddress addr(strAddr, NODE_NETWORK);\r
363             addr.nTime = 0; // so it won't relay unless successfully connected\r
364             if (addr.IsValid())\r
365                 AddAddress(addr);\r
366         }\r
367     }\r
368 \r
369     if (mapArgs.count("-paytxfee"))\r
370     {\r
371         if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))\r
372         {\r
373             wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");\r
374             return false;\r
375         }\r
376         if (nTransactionFee > 1 * COIN)\r
377             wxMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), "Bitcoin");\r
378     }\r
379 \r
380     //\r
381     // Create the main window and start the node\r
382     //\r
383 #ifdef GUI\r
384     if (!fDaemon)\r
385         CreateMainWindow();\r
386 #endif\r
387 \r
388     if (!CheckDiskSpace())\r
389         return false;\r
390 \r
391     RandAddSeedPerfmon();\r
392 \r
393     if (!CreateThread(StartNode, NULL))\r
394         wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");\r
395 \r
396     if (mapArgs.count("-server") || fDaemon)\r
397         CreateThread(ThreadRPCServer, NULL);\r
398 \r
399 #if defined(__WXMSW__) && defined(GUI)\r
400     if (fFirstRun)\r
401         SetStartOnSystemStartup(true);\r
402 #endif\r
403 \r
404     return true;\r
405 }\r