flush wallet.dat, multi-proc, reorg options, revert to startup folder shortcut
[novacoin.git] / util.cpp
1 // Copyright (c) 2009 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 bool fDebug = false;\r
10 \r
11 \r
12 \r
13 \r
14 // Init openssl library multithreading support\r
15 static HANDLE* lock_cs;\r
16 \r
17 void win32_locking_callback(int mode, int type, const char* file, int line)\r
18 {\r
19     if (mode & CRYPTO_LOCK)\r
20         WaitForSingleObject(lock_cs[type], INFINITE);\r
21     else\r
22         ReleaseMutex(lock_cs[type]);\r
23 }\r
24 \r
25 // Init\r
26 class CInit\r
27 {\r
28 public:\r
29     CInit()\r
30     {\r
31         // Init openssl library multithreading support\r
32         lock_cs = (HANDLE*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(HANDLE));\r
33         for (int i = 0; i < CRYPTO_num_locks(); i++)\r
34             lock_cs[i] = CreateMutex(NULL,FALSE,NULL);\r
35         CRYPTO_set_locking_callback(win32_locking_callback);\r
36 \r
37         // Seed random number generator with screen scrape and other hardware sources\r
38         RAND_screen();\r
39 \r
40         // Seed random number generator with perfmon data\r
41         RandAddSeed(true);\r
42     }\r
43     ~CInit()\r
44     {\r
45         // Shutdown openssl library multithreading support\r
46         CRYPTO_set_locking_callback(NULL);\r
47         for (int i =0 ; i < CRYPTO_num_locks(); i++)\r
48             CloseHandle(lock_cs[i]);\r
49         OPENSSL_free(lock_cs);\r
50     }\r
51 }\r
52 instance_of_cinit;\r
53 \r
54 \r
55 \r
56 \r
57 void RandAddSeed(bool fPerfmon)\r
58 {\r
59     // Seed with CPU performance counter\r
60     LARGE_INTEGER PerformanceCount;\r
61     QueryPerformanceCounter(&PerformanceCount);\r
62     RAND_add(&PerformanceCount, sizeof(PerformanceCount), 1.5);\r
63     memset(&PerformanceCount, 0, sizeof(PerformanceCount));\r
64 \r
65     static int64 nLastPerfmon;\r
66     if (fPerfmon || GetTime() > nLastPerfmon + 5 * 60)\r
67     {\r
68         nLastPerfmon = GetTime();\r
69 \r
70         // Seed with the entire set of perfmon data\r
71         unsigned char pdata[250000];\r
72         memset(pdata, 0, sizeof(pdata));\r
73         unsigned long nSize = sizeof(pdata);\r
74         long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);\r
75         RegCloseKey(HKEY_PERFORMANCE_DATA);\r
76         if (ret == ERROR_SUCCESS)\r
77         {\r
78             uint256 hash;\r
79             SHA256(pdata, nSize, (unsigned char*)&hash);\r
80             RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));\r
81             hash = 0;\r
82             memset(pdata, 0, nSize);\r
83 \r
84             time_t nTime;\r
85             time(&nTime);\r
86             struct tm* ptmTime = gmtime(&nTime);\r
87             char pszTime[200];\r
88             strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime);\r
89             printf("%s RandAddSeed() %d bytes\n", pszTime, nSize);\r
90         }\r
91     }\r
92 }\r
93 \r
94 \r
95 \r
96 \r
97 \r
98 \r
99 \r
100 \r
101 \r
102 \r
103 // Safer snprintf\r
104 //  - prints up to limit-1 characters\r
105 //  - output string is always null terminated even if limit reached\r
106 //  - return value is the number of characters actually printed\r
107 int my_snprintf(char* buffer, size_t limit, const char* format, ...)\r
108 {\r
109     if (limit == 0)\r
110         return 0;\r
111     va_list arg_ptr;\r
112     va_start(arg_ptr, format);\r
113     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
114     va_end(arg_ptr);\r
115     if (ret < 0 || ret >= limit)\r
116     {\r
117         ret = limit - 1;\r
118         buffer[limit-1] = 0;\r
119     }\r
120     return ret;\r
121 }\r
122 \r
123 \r
124 string strprintf(const char* format, ...)\r
125 {\r
126     char buffer[50000];\r
127     char* p = buffer;\r
128     int limit = sizeof(buffer);\r
129     int ret;\r
130     loop\r
131     {\r
132         va_list arg_ptr;\r
133         va_start(arg_ptr, format);\r
134         ret = _vsnprintf(p, limit, format, arg_ptr);\r
135         va_end(arg_ptr);\r
136         if (ret >= 0 && ret < limit)\r
137             break;\r
138         if (p != buffer)\r
139             delete p;\r
140         limit *= 2;\r
141         p = new char[limit];\r
142         if (p == NULL)\r
143             throw std::bad_alloc();\r
144     }\r
145 #ifdef _MSC_VER\r
146     // msvc optimisation\r
147     if (p == buffer)\r
148         return string(p, p+ret);\r
149 #endif\r
150     string str(p, p+ret);\r
151     if (p != buffer)\r
152         delete p;\r
153     return str;\r
154 }\r
155 \r
156 \r
157 bool error(const char* format, ...)\r
158 {\r
159     char buffer[50000];\r
160     int limit = sizeof(buffer);\r
161     va_list arg_ptr;\r
162     va_start(arg_ptr, format);\r
163     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
164     va_end(arg_ptr);\r
165     if (ret < 0 || ret >= limit)\r
166     {\r
167         ret = limit - 1;\r
168         buffer[limit-1] = 0;\r
169     }\r
170     printf("ERROR: %s\n", buffer);\r
171     return false;\r
172 }\r
173 \r
174 \r
175 void PrintException(std::exception* pex, const char* pszThread)\r
176 {\r
177     char pszModule[MAX_PATH];\r
178     pszModule[0] = '\0';\r
179     GetModuleFileName(NULL, pszModule, sizeof(pszModule));\r
180     _strlwr(pszModule);\r
181     char pszMessage[1000];\r
182     if (pex)\r
183         snprintf(pszMessage, sizeof(pszMessage),\r
184             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);\r
185     else\r
186         snprintf(pszMessage, sizeof(pszMessage),\r
187             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);\r
188     printf("\n\n************************\n%s", pszMessage);\r
189     if (wxTheApp)\r
190         wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);\r
191     throw;\r
192     //DebugBreak();\r
193 }\r
194 \r
195 \r
196 void ParseString(const string& str, char c, vector<string>& v)\r
197 {\r
198     unsigned int i1 = 0;\r
199     unsigned int i2;\r
200     do\r
201     {\r
202         i2 = str.find(c, i1);\r
203         v.push_back(str.substr(i1, i2-i1));\r
204         i1 = i2+1;\r
205     }\r
206     while (i2 != str.npos);\r
207 }\r
208 \r
209 \r
210 string FormatMoney(int64 n, bool fPlus)\r
211 {\r
212     n /= CENT;\r
213     string str = strprintf("%I64d.%02I64d", (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);\r
214     for (int i = 6; i < str.size(); i += 4)\r
215         if (isdigit(str[str.size() - i - 1]))\r
216             str.insert(str.size() - i, 1, ',');\r
217     if (n < 0)\r
218         str.insert((unsigned int)0, 1, '-');\r
219     else if (fPlus && n > 0)\r
220         str.insert((unsigned int)0, 1, '+');\r
221     return str;\r
222 }\r
223 \r
224 bool ParseMoney(const char* pszIn, int64& nRet)\r
225 {\r
226     string strWhole;\r
227     int64 nCents = 0;\r
228     const char* p = pszIn;\r
229     while (isspace(*p))\r
230         p++;\r
231     for (; *p; p++)\r
232     {\r
233         if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))\r
234             continue;\r
235         if (*p == '.')\r
236         {\r
237             p++;\r
238             if (isdigit(*p))\r
239             {\r
240                 nCents = 10 * (*p++ - '0');\r
241                 if (isdigit(*p))\r
242                     nCents += (*p++ - '0');\r
243             }\r
244             break;\r
245         }\r
246         if (isspace(*p))\r
247             break;\r
248         if (!isdigit(*p))\r
249             return false;\r
250         strWhole.insert(strWhole.end(), *p);\r
251     }\r
252     for (; *p; p++)\r
253         if (!isspace(*p))\r
254             return false;\r
255     if (strWhole.size() > 14)\r
256         return false;\r
257     if (nCents < 0 || nCents > 99)\r
258         return false;\r
259     int64 nWhole = atoi64(strWhole);\r
260     int64 nPreValue = nWhole * 100 + nCents;\r
261     int64 nValue = nPreValue * CENT;\r
262     if (nValue / CENT != nPreValue)\r
263         return false;\r
264     if (nValue / COIN != nWhole)\r
265         return false;\r
266     nRet = nValue;\r
267     return true;\r
268 }\r
269 \r
270 \r
271 \r
272 \r
273 \r
274 \r
275 \r
276 \r
277 \r
278 \r
279 bool FileExists(const char* psz)\r
280 {\r
281 #ifdef WIN32\r
282     return GetFileAttributes(psz) != -1;\r
283 #else\r
284     return access(psz, 0) != -1;\r
285 #endif\r
286 }\r
287 \r
288 int GetFilesize(FILE* file)\r
289 {\r
290     int nSavePos = ftell(file);\r
291     int nFilesize = -1;\r
292     if (fseek(file, 0, SEEK_END) == 0)\r
293         nFilesize = ftell(file);\r
294     fseek(file, nSavePos, SEEK_SET);\r
295     return nFilesize;\r
296 }\r
297 \r
298 \r
299 \r
300 \r
301 \r
302 \r
303 \r
304 \r
305 uint64 GetRand(uint64 nMax)\r
306 {\r
307     if (nMax == 0)\r
308         return 0;\r
309 \r
310     // The range of the random source must be a multiple of the modulus\r
311     // to give every possible output value an equal possibility\r
312     uint64 nRange = (_UI64_MAX / nMax) * nMax;\r
313     uint64 nRand = 0;\r
314     do\r
315         RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
316     while (nRand >= nRange);\r
317     return (nRand % nMax);\r
318 }\r
319 \r
320 \r
321 \r
322 \r
323 \r
324 \r
325 \r
326 \r
327 \r
328 \r
329 //\r
330 // "Never go to sea with two chronometers; take one or three."\r
331 // Our three chronometers are:\r
332 //  - System clock\r
333 //  - Median of other server's clocks\r
334 //  - NTP servers\r
335 //\r
336 // note: NTP isn't implemented yet, so until then we just use the median\r
337 //  of other nodes clocks to correct ours.\r
338 //\r
339 \r
340 int64 GetTime()\r
341 {\r
342     return time(NULL);\r
343 }\r
344 \r
345 static int64 nTimeOffset = 0;\r
346 \r
347 int64 GetAdjustedTime()\r
348 {\r
349     return GetTime() + nTimeOffset;\r
350 }\r
351 \r
352 void AddTimeData(unsigned int ip, int64 nTime)\r
353 {\r
354     int64 nOffsetSample = nTime - GetTime();\r
355 \r
356     // Ignore duplicates\r
357     static set<unsigned int> setKnown;\r
358     if (!setKnown.insert(ip).second)\r
359         return;\r
360 \r
361     // Add data\r
362     static vector<int64> vTimeOffsets;\r
363     if (vTimeOffsets.empty())\r
364         vTimeOffsets.push_back(0);\r
365     vTimeOffsets.push_back(nOffsetSample);\r
366     printf("Added time data, samples %d, ip %08x, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), ip, vTimeOffsets.back(), vTimeOffsets.back()/60);\r
367     if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)\r
368     {\r
369         sort(vTimeOffsets.begin(), vTimeOffsets.end());\r
370         int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];\r
371         nTimeOffset = nMedian;\r
372         if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60)\r
373         {\r
374             // Only let other nodes change our clock so far before we\r
375             // go to the NTP servers\r
376             /// todo: Get time from NTP servers, then set a flag\r
377             ///    to make sure it doesn't get changed again\r
378         }\r
379         foreach(int64 n, vTimeOffsets)\r
380             printf("%+I64d  ", n);\r
381         printf("|  nTimeOffset = %+I64d  (%+I64d minutes)\n", nTimeOffset, nTimeOffset/60);\r
382     }\r
383 }\r