Projects : bitcoin : bitcoin_dumpblock_no_losers
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 "knobs.h" |
6 | #include "headers.h" |
7 | #include "strlcpy.h" |
8 | #include <boost/program_options/detail/config_file.hpp> |
9 | #include <boost/program_options/parsers.hpp> |
10 | #include <boost/filesystem.hpp> |
11 | #include <boost/filesystem/fstream.hpp> |
12 | #include <boost/interprocess/sync/interprocess_mutex.hpp> |
13 | #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> |
14 | #include <boost/foreach.hpp> |
15 | |
16 | using namespace std; |
17 | using namespace boost; |
18 | |
19 | map<string, string> mapArgs; |
20 | map<string, vector<string> > mapMultiArgs; |
21 | bool fDebug = false; |
22 | bool fPrintToConsole = false; |
23 | bool fPrintToDebugger = false; |
24 | bool fCanEat = false; |
25 | bool fVerifyAll = false; |
26 | char pszSetDataDir[MAX_PATH] = ""; |
27 | bool fRequestShutdown = false; |
28 | bool fShutdown = false; |
29 | bool fDaemon = false; |
30 | bool fServer = false; |
31 | bool fCommandLine = false; |
32 | string strMiscWarning; |
33 | bool fNoListen = false; |
34 | bool fLogTimestamps = false; |
35 | bool fLowS = false; |
36 | bool fHighS = false; |
37 | |
38 | std::string CLIENT_NAME(DEFAULT_CLIENT_NAME); |
39 | |
40 | |
41 | // Workaround for "multiple definition of `_tls_used'" |
42 | // http://svn.boost.org/trac/boost/ticket/4258 |
43 | extern "C" void tss_cleanup_implemented() { } |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | // Init openssl library multithreading support |
50 | static boost::interprocess::interprocess_mutex** ppmutexOpenSSL; |
51 | void locking_callback(int mode, int i, const char* file, int line) |
52 | { |
53 | if (mode & CRYPTO_LOCK) |
54 | ppmutexOpenSSL[i]->lock(); |
55 | else |
56 | ppmutexOpenSSL[i]->unlock(); |
57 | } |
58 | |
59 | // Init |
60 | class CInit |
61 | { |
62 | public: |
63 | CInit() |
64 | { |
65 | // Init openssl library multithreading support |
66 | ppmutexOpenSSL = (boost::interprocess::interprocess_mutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex*)); |
67 | for (int i = 0; i < CRYPTO_num_locks(); i++) |
68 | ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex(); |
69 | CRYPTO_set_locking_callback(locking_callback); |
70 | |
71 | // Seed random number generator with performance counter |
72 | RandAddSeed(); |
73 | } |
74 | ~CInit() |
75 | { |
76 | // Shutdown openssl library multithreading support |
77 | CRYPTO_set_locking_callback(NULL); |
78 | for (int i = 0; i < CRYPTO_num_locks(); i++) |
79 | delete ppmutexOpenSSL[i]; |
80 | OPENSSL_free(ppmutexOpenSSL); |
81 | } |
82 | } |
83 | instance_of_cinit; |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | void RandAddSeed() |
93 | { |
94 | // Seed with CPU performance counter |
95 | int64 nCounter = GetPerformanceCounter(); |
96 | RAND_add(&nCounter, sizeof(nCounter), 1.5); |
97 | memset(&nCounter, 0, sizeof(nCounter)); |
98 | } |
99 | |
100 | void RandAddSeedPerfmon() |
101 | { |
102 | RandAddSeed(); |
103 | |
104 | // This can take up to 2 seconds, so only do it every 10 minutes |
105 | static int64 nLastPerfmon; |
106 | if (GetTime() < nLastPerfmon + 10 * 60) |
107 | return; |
108 | nLastPerfmon = GetTime(); |
109 | |
110 | } |
111 | |
112 | uint64 GetRand(uint64 nMax) |
113 | { |
114 | if (nMax == 0) |
115 | return 0; |
116 | |
117 | // The range of the random source must be a multiple of the modulus |
118 | // to give every possible output value an equal possibility |
119 | uint64 nRange = (UINT64_MAX / nMax) * nMax; |
120 | uint64 nRand = 0; |
121 | do |
122 | RAND_bytes((unsigned char*)&nRand, sizeof(nRand)); |
123 | while (nRand >= nRange); |
124 | return (nRand % nMax); |
125 | } |
126 | |
127 | int GetRandInt(int nMax) |
128 | { |
129 | return GetRand(nMax); |
130 | } |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | inline int OutputDebugStringF(const char* pszFormat, ...) |
143 | { |
144 | int ret = 0; |
145 | if (fPrintToConsole) |
146 | { |
147 | // print to console |
148 | va_list arg_ptr; |
149 | va_start(arg_ptr, pszFormat); |
150 | ret = vprintf(pszFormat, arg_ptr); |
151 | va_end(arg_ptr); |
152 | } |
153 | else |
154 | { |
155 | // print to debug.log |
156 | static FILE* fileout = NULL; |
157 | |
158 | if (!fileout) |
159 | { |
160 | char pszFile[MAX_PATH+100]; |
161 | GetDataDir(pszFile); |
162 | strlcat(pszFile, "/debug.log", sizeof(pszFile)); |
163 | fileout = fopen(pszFile, "a"); |
164 | if (fileout) setbuf(fileout, NULL); // unbuffered |
165 | } |
166 | if (fileout) |
167 | { |
168 | static bool fStartedNewLine = true; |
169 | |
170 | // Debug print useful for profiling |
171 | if (fLogTimestamps && fStartedNewLine) |
172 | fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); |
173 | if (pszFormat[strlen(pszFormat) - 1] == '\n') |
174 | fStartedNewLine = true; |
175 | else |
176 | fStartedNewLine = false; |
177 | |
178 | va_list arg_ptr; |
179 | va_start(arg_ptr, pszFormat); |
180 | ret = vfprintf(fileout, pszFormat, arg_ptr); |
181 | va_end(arg_ptr); |
182 | } |
183 | } |
184 | |
185 | return ret; |
186 | } |
187 | |
188 | |
189 | // Safer snprintf |
190 | // - prints up to limit-1 characters |
191 | // - output string is always null terminated even if limit reached |
192 | // - return value is the number of characters actually printed |
193 | int my_snprintf(char* buffer, size_t limit, const char* format, ...) |
194 | { |
195 | if (limit == 0) |
196 | return 0; |
197 | va_list arg_ptr; |
198 | va_start(arg_ptr, format); |
199 | int ret = _vsnprintf(buffer, limit, format, arg_ptr); |
200 | va_end(arg_ptr); |
201 | if (ret < 0 || ret >= limit) |
202 | { |
203 | ret = limit - 1; |
204 | buffer[limit-1] = 0; |
205 | } |
206 | return ret; |
207 | } |
208 | |
209 | string strprintf(const std::string &format, ...) |
210 | { |
211 | char buffer[50000]; |
212 | char* p = buffer; |
213 | int limit = sizeof(buffer); |
214 | int ret; |
215 | loop |
216 | { |
217 | va_list arg_ptr; |
218 | va_start(arg_ptr, format); |
219 | ret = _vsnprintf(p, limit, format.c_str(), arg_ptr); |
220 | va_end(arg_ptr); |
221 | if (ret >= 0 && ret < limit) |
222 | break; |
223 | if (p != buffer) |
224 | delete[] p; |
225 | limit *= 2; |
226 | p = new char[limit]; |
227 | if (p == NULL) |
228 | throw std::bad_alloc(); |
229 | } |
230 | string str(p, p+ret); |
231 | if (p != buffer) |
232 | delete[] p; |
233 | return str; |
234 | } |
235 | |
236 | bool error(const std::string &format, ...) |
237 | { |
238 | char buffer[50000]; |
239 | int limit = sizeof(buffer); |
240 | va_list arg_ptr; |
241 | va_start(arg_ptr, format); |
242 | int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr); |
243 | va_end(arg_ptr); |
244 | if (ret < 0 || ret >= limit) |
245 | { |
246 | ret = limit - 1; |
247 | buffer[limit-1] = 0; |
248 | } |
249 | printf("ERROR: %s\n", buffer); |
250 | return false; |
251 | } |
252 | |
253 | |
254 | void ParseString(const string& str, char c, vector<string>& v) |
255 | { |
256 | if (str.empty()) |
257 | return; |
258 | string::size_type i1 = 0; |
259 | string::size_type i2; |
260 | loop |
261 | { |
262 | i2 = str.find(c, i1); |
263 | if (i2 == str.npos) |
264 | { |
265 | v.push_back(str.substr(i1)); |
266 | return; |
267 | } |
268 | v.push_back(str.substr(i1, i2-i1)); |
269 | i1 = i2+1; |
270 | } |
271 | } |
272 | |
273 | |
274 | string FormatMoney(int64 n, bool fPlus) |
275 | { |
276 | // Note: not using straight sprintf here because we do NOT want |
277 | // localized number formatting. |
278 | int64 n_abs = (n > 0 ? n : -n); |
279 | int64 quotient = n_abs/COIN; |
280 | int64 remainder = n_abs%COIN; |
281 | string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder); |
282 | |
283 | // Right-trim excess 0's before the decimal point: |
284 | int nTrim = 0; |
285 | for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i) |
286 | ++nTrim; |
287 | if (nTrim) |
288 | str.erase(str.size()-nTrim, nTrim); |
289 | |
290 | if (n < 0) |
291 | str.insert((unsigned int)0, 1, '-'); |
292 | else if (fPlus && n > 0) |
293 | str.insert((unsigned int)0, 1, '+'); |
294 | return str; |
295 | } |
296 | |
297 | |
298 | bool ParseMoney(const string& str, int64& nRet) |
299 | { |
300 | return ParseMoney(str.c_str(), nRet); |
301 | } |
302 | |
303 | bool ParseMoney(const char* pszIn, int64& nRet) |
304 | { |
305 | string strWhole; |
306 | int64 nUnits = 0; |
307 | const char* p = pszIn; |
308 | while (isspace(*p)) |
309 | p++; |
310 | for (; *p; p++) |
311 | { |
312 | if (*p == '.') |
313 | { |
314 | p++; |
315 | int64 nMult = CENT*10; |
316 | while (isdigit(*p) && (nMult > 0)) |
317 | { |
318 | nUnits += nMult * (*p++ - '0'); |
319 | nMult /= 10; |
320 | } |
321 | break; |
322 | } |
323 | if (isspace(*p)) |
324 | break; |
325 | if (!isdigit(*p)) |
326 | return false; |
327 | strWhole.insert(strWhole.end(), *p); |
328 | } |
329 | for (; *p; p++) |
330 | if (!isspace(*p)) |
331 | return false; |
332 | if (strWhole.size() > 10) // guard against 63 bit overflow |
333 | return false; |
334 | if (nUnits < 0 || nUnits > COIN) |
335 | return false; |
336 | int64 nWhole = atoi64(strWhole); |
337 | int64 nValue = nWhole*COIN + nUnits; |
338 | |
339 | nRet = nValue; |
340 | return true; |
341 | } |
342 | |
343 | |
344 | vector<unsigned char> ParseHex(const char* psz) |
345 | { |
346 | static char phexdigit[256] = |
347 | { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
348 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
349 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
350 | 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, |
351 | -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
352 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
353 | -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
354 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
355 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
356 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
357 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
358 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
359 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
360 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
361 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
362 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; |
363 | |
364 | // convert hex dump to vector |
365 | vector<unsigned char> vch; |
366 | loop |
367 | { |
368 | while (isspace(*psz)) |
369 | psz++; |
370 | char c = phexdigit[(unsigned char)*psz++]; |
371 | if (c == (char)-1) |
372 | break; |
373 | unsigned char n = (c << 4); |
374 | c = phexdigit[(unsigned char)*psz++]; |
375 | if (c == (char)-1) |
376 | break; |
377 | n |= c; |
378 | vch.push_back(n); |
379 | } |
380 | return vch; |
381 | } |
382 | |
383 | vector<unsigned char> ParseHex(const string& str) |
384 | { |
385 | return ParseHex(str.c_str()); |
386 | } |
387 | |
388 | void ParseParameters(int argc, char* argv[]) |
389 | { |
390 | mapArgs.clear(); |
391 | mapMultiArgs.clear(); |
392 | for (int i = 1; i < argc; i++) |
393 | { |
394 | char psz[10000]; |
395 | strlcpy(psz, argv[i], sizeof(psz)); |
396 | char* pszValue = (char*)""; |
397 | if (strchr(psz, '=')) |
398 | { |
399 | pszValue = strchr(psz, '='); |
400 | *pszValue++ = '\0'; |
401 | } |
402 | if (psz[0] != '-') |
403 | break; |
404 | mapArgs[psz] = pszValue; |
405 | mapMultiArgs[psz].push_back(pszValue); |
406 | } |
407 | } |
408 | |
409 | bool SoftSetArg(const std::string& strArg, const std::string& strValue) |
410 | { |
411 | if (mapArgs.count(strArg)) |
412 | return false; |
413 | mapArgs[strArg] = strValue; |
414 | return true; |
415 | } |
416 | |
417 | bool SoftSetArg(const std::string& strArg, bool fValue) |
418 | { |
419 | if (fValue) |
420 | return SoftSetArg(strArg, std::string("1")); |
421 | else |
422 | return SoftSetArg(strArg, std::string("0")); |
423 | } |
424 | |
425 | |
426 | string EncodeBase64(const unsigned char* pch, size_t len) |
427 | { |
428 | static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
429 | |
430 | string strRet=""; |
431 | strRet.reserve((len+2)/3*4); |
432 | |
433 | int mode=0, left=0; |
434 | const unsigned char *pchEnd = pch+len; |
435 | |
436 | while (pch<pchEnd) |
437 | { |
438 | int enc = *(pch++); |
439 | switch (mode) |
440 | { |
441 | case 0: // we have no bits |
442 | strRet += pbase64[enc >> 2]; |
443 | left = (enc & 3) << 4; |
444 | mode = 1; |
445 | break; |
446 | |
447 | case 1: // we have two bits |
448 | strRet += pbase64[left | (enc >> 4)]; |
449 | left = (enc & 15) << 2; |
450 | mode = 2; |
451 | break; |
452 | |
453 | case 2: // we have four bits |
454 | strRet += pbase64[left | (enc >> 6)]; |
455 | strRet += pbase64[enc & 63]; |
456 | mode = 0; |
457 | break; |
458 | } |
459 | } |
460 | |
461 | if (mode) |
462 | { |
463 | strRet += pbase64[left]; |
464 | strRet += '='; |
465 | if (mode == 1) |
466 | strRet += '='; |
467 | } |
468 | |
469 | return strRet; |
470 | } |
471 | |
472 | string EncodeBase64(const string& str) |
473 | { |
474 | return EncodeBase64((const unsigned char*)str.c_str(), str.size()); |
475 | } |
476 | |
477 | vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) |
478 | { |
479 | static const int decode64_table[256] = |
480 | { |
481 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
482 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
483 | -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, |
484 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
485 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, |
486 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
487 | 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
488 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
489 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
490 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
491 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
492 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
493 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 |
494 | }; |
495 | |
496 | if (pfInvalid) |
497 | *pfInvalid = false; |
498 | |
499 | vector<unsigned char> vchRet; |
500 | vchRet.reserve(strlen(p)*3/4); |
501 | |
502 | int mode = 0; |
503 | int left = 0; |
504 | |
505 | while (1) |
506 | { |
507 | int dec = decode64_table[*p]; |
508 | if (dec == -1) break; |
509 | p++; |
510 | switch (mode) |
511 | { |
512 | case 0: // we have no bits and get 6 |
513 | left = dec; |
514 | mode = 1; |
515 | break; |
516 | |
517 | case 1: // we have 6 bits and keep 4 |
518 | vchRet.push_back((left<<2) | (dec>>4)); |
519 | left = dec & 15; |
520 | mode = 2; |
521 | break; |
522 | |
523 | case 2: // we have 4 bits and get 6, we keep 2 |
524 | vchRet.push_back((left<<4) | (dec>>2)); |
525 | left = dec & 3; |
526 | mode = 3; |
527 | break; |
528 | |
529 | case 3: // we have 2 bits and get 6 |
530 | vchRet.push_back((left<<6) | dec); |
531 | mode = 0; |
532 | break; |
533 | } |
534 | } |
535 | |
536 | if (pfInvalid) |
537 | switch (mode) |
538 | { |
539 | case 0: // 4n base64 characters processed: ok |
540 | break; |
541 | |
542 | case 1: // 4n+1 base64 character processed: impossible |
543 | *pfInvalid = true; |
544 | break; |
545 | |
546 | case 2: // 4n+2 base64 characters processed: require '==' |
547 | if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1) |
548 | *pfInvalid = true; |
549 | break; |
550 | |
551 | case 3: // 4n+3 base64 characters processed: require '=' |
552 | if (left || p[0] != '=' || decode64_table[p[1]] != -1) |
553 | *pfInvalid = true; |
554 | break; |
555 | } |
556 | |
557 | return vchRet; |
558 | } |
559 | |
560 | string DecodeBase64(const string& str) |
561 | { |
562 | vector<unsigned char> vchRet = DecodeBase64(str.c_str()); |
563 | return string((const char*)&vchRet[0], vchRet.size()); |
564 | } |
565 | |
566 | |
567 | bool WildcardMatch(const char* psz, const char* mask) |
568 | { |
569 | loop |
570 | { |
571 | switch (*mask) |
572 | { |
573 | case '\0': |
574 | return (*psz == '\0'); |
575 | case '*': |
576 | return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask)); |
577 | case '?': |
578 | if (*psz == '\0') |
579 | return false; |
580 | break; |
581 | default: |
582 | if (*psz != *mask) |
583 | return false; |
584 | break; |
585 | } |
586 | psz++; |
587 | mask++; |
588 | } |
589 | } |
590 | |
591 | bool WildcardMatch(const string& str, const string& mask) |
592 | { |
593 | return WildcardMatch(str.c_str(), mask.c_str()); |
594 | } |
595 | |
596 | |
597 | |
598 | |
599 | |
600 | |
601 | |
602 | |
603 | void FormatException(char* pszMessage, std::exception* pex, const char* pszThread) |
604 | { |
605 | const char* pszModule = "bitcoin"; |
606 | if (pex) |
607 | snprintf(pszMessage, 1000, |
608 | "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); |
609 | else |
610 | snprintf(pszMessage, 1000, |
611 | "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); |
612 | } |
613 | |
614 | void LogException(std::exception* pex, const char* pszThread) |
615 | { |
616 | char pszMessage[10000]; |
617 | FormatException(pszMessage, pex, pszThread); |
618 | printf("\n%s", pszMessage); |
619 | } |
620 | |
621 | void PrintException(std::exception* pex, const char* pszThread) |
622 | { |
623 | char pszMessage[10000]; |
624 | FormatException(pszMessage, pex, pszThread); |
625 | printf("\n\n************************\n%s\n", pszMessage); |
626 | fprintf(stderr, "\n\n************************\n%s\n", pszMessage); |
627 | strMiscWarning = pszMessage; |
628 | throw; |
629 | } |
630 | |
631 | void ThreadOneMessageBox(string strMessage) |
632 | { |
633 | // Skip message boxes if one is already open |
634 | static bool fMessageBoxOpen; |
635 | if (fMessageBoxOpen) |
636 | return; |
637 | fMessageBoxOpen = true; |
638 | ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION); |
639 | fMessageBoxOpen = false; |
640 | } |
641 | |
642 | void PrintExceptionContinue(std::exception* pex, const char* pszThread) |
643 | { |
644 | char pszMessage[10000]; |
645 | FormatException(pszMessage, pex, pszThread); |
646 | printf("\n\n************************\n%s\n", pszMessage); |
647 | fprintf(stderr, "\n\n************************\n%s\n", pszMessage); |
648 | strMiscWarning = pszMessage; |
649 | } |
650 | |
651 | string GetDefaultDataDir() |
652 | { |
653 | // Mac: ~/Library/Application Support/Bitcoin |
654 | // Unix: ~/.bitcoin |
655 | char* pszHome = getenv("HOME"); |
656 | if (pszHome == NULL || strlen(pszHome) == 0) |
657 | pszHome = (char*)"/"; |
658 | string strHome = pszHome; |
659 | if (strHome[strHome.size()-1] != '/') |
660 | strHome += '/'; |
661 | #ifdef MAC_OSX |
662 | // Mac |
663 | strHome += "Library/Application Support/"; |
664 | filesystem::create_directory(strHome.c_str()); |
665 | return strHome + "Bitcoin"; |
666 | #else |
667 | // Unix |
668 | return strHome + ".bitcoin"; |
669 | #endif |
670 | } |
671 | |
672 | void GetDataDir(char* pszDir) |
673 | { |
674 | // pszDir must be at least MAX_PATH length. |
675 | int nVariation; |
676 | if (pszSetDataDir[0] != 0) |
677 | { |
678 | strlcpy(pszDir, pszSetDataDir, MAX_PATH); |
679 | nVariation = 0; |
680 | } |
681 | else |
682 | { |
683 | // This can be called during exceptions by printf, so we cache the |
684 | // value so we don't have to do memory allocations after that. |
685 | static char pszCachedDir[MAX_PATH]; |
686 | if (pszCachedDir[0] == 0) |
687 | strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir)); |
688 | strlcpy(pszDir, pszCachedDir, MAX_PATH); |
689 | nVariation = 1; |
690 | } |
691 | static bool pfMkdir[4]; |
692 | if (!pfMkdir[nVariation]) |
693 | { |
694 | pfMkdir[nVariation] = true; |
695 | boost::filesystem::create_directory(pszDir); |
696 | } |
697 | } |
698 | |
699 | string GetDataDir() |
700 | { |
701 | char pszDir[MAX_PATH]; |
702 | GetDataDir(pszDir); |
703 | return pszDir; |
704 | } |
705 | |
706 | string GetConfigFile() |
707 | { |
708 | namespace fs = boost::filesystem; |
709 | fs::path pathConfig(GetArg("-conf", "bitcoin.conf")); |
710 | if (!pathConfig.is_complete()) |
711 | pathConfig = fs::path(GetDataDir()) / pathConfig; |
712 | return pathConfig.string(); |
713 | } |
714 | |
715 | void ReadConfigFile(map<string, string>& mapSettingsRet, |
716 | map<string, vector<string> >& mapMultiSettingsRet) |
717 | { |
718 | namespace fs = boost::filesystem; |
719 | namespace pod = boost::program_options::detail; |
720 | |
721 | fs::ifstream streamConfig(GetConfigFile()); |
722 | if (!streamConfig.good()) |
723 | return; |
724 | |
725 | set<string> setOptions; |
726 | setOptions.insert("*"); |
727 | |
728 | for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) |
729 | { |
730 | // Don't overwrite existing settings so command line settings override bitcoin.conf |
731 | string strKey = string("-") + it->string_key; |
732 | if (mapSettingsRet.count(strKey) == 0) |
733 | mapSettingsRet[strKey] = it->value[0]; |
734 | mapMultiSettingsRet[strKey].push_back(it->value[0]); |
735 | } |
736 | } |
737 | |
738 | string GetPidFile() |
739 | { |
740 | namespace fs = boost::filesystem; |
741 | fs::path pathConfig(GetArg("-pid", "bitcoind.pid")); |
742 | if (!pathConfig.is_complete()) |
743 | pathConfig = fs::path(GetDataDir()) / pathConfig; |
744 | return pathConfig.string(); |
745 | } |
746 | |
747 | void CreatePidFile(string pidFile, pid_t pid) |
748 | { |
749 | FILE* file = fopen(pidFile.c_str(), "w"); |
750 | if (file) |
751 | { |
752 | fprintf(file, "%d\n", pid); |
753 | fclose(file); |
754 | } |
755 | } |
756 | |
757 | int GetFilesize(FILE* file) |
758 | { |
759 | int nSavePos = ftell(file); |
760 | int nFilesize = -1; |
761 | if (fseek(file, 0, SEEK_END) == 0) |
762 | nFilesize = ftell(file); |
763 | fseek(file, nSavePos, SEEK_SET); |
764 | return nFilesize; |
765 | } |
766 | |
767 | void ShrinkDebugFile() |
768 | { |
769 | // Scroll debug.log if it's getting too big |
770 | string strFile = GetDataDir() + "/debug.log"; |
771 | FILE* file = fopen(strFile.c_str(), "r"); |
772 | if (file && GetFilesize(file) > 10 * 1000000) |
773 | { |
774 | // Restart the file with some of the end |
775 | char pch[200000]; |
776 | fseek(file, -sizeof(pch), SEEK_END); |
777 | int nBytes = fread(pch, 1, sizeof(pch), file); |
778 | fclose(file); |
779 | |
780 | file = fopen(strFile.c_str(), "w"); |
781 | if (file) |
782 | { |
783 | fwrite(pch, 1, nBytes, file); |
784 | fclose(file); |
785 | } |
786 | } |
787 | } |
788 | |
789 | |
790 | |
791 | |
792 | |
793 | |
794 | |
795 | |
796 | // |
797 | // "Never go to sea with two chronometers; take one or three." |
798 | // Our three time sources are: |
799 | // - System clock |
800 | // - Median of other nodes's clocks |
801 | // - The user (asking the user to fix the system clock if the first two disagree) |
802 | // |
803 | static int64 nMockTime = 0; // For unit testing |
804 | |
805 | int64 GetTime() |
806 | { |
807 | if (nMockTime) return nMockTime; |
808 | |
809 | return time(NULL); |
810 | } |
811 | |
812 | void SetMockTime(int64 nMockTimeIn) |
813 | { |
814 | nMockTime = nMockTimeIn; |
815 | } |
816 | |
817 | static int64 nTimeOffset = 0; |
818 | |
819 | int64 GetAdjustedTime() |
820 | { |
821 | return GetTime() + nTimeOffset; |
822 | } |
823 | |
824 | void AddTimeData(unsigned int ip, int64 nTime) |
825 | { |
826 | int64 nOffsetSample = nTime - GetTime(); |
827 | |
828 | // Ignore duplicates |
829 | static set<unsigned int> setKnown; |
830 | if (!setKnown.insert(ip).second) |
831 | return; |
832 | |
833 | // Add data |
834 | static vector<int64> vTimeOffsets; |
835 | if (vTimeOffsets.empty()) |
836 | vTimeOffsets.push_back(0); |
837 | vTimeOffsets.push_back(nOffsetSample); |
838 | printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60); |
839 | if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) |
840 | { |
841 | sort(vTimeOffsets.begin(), vTimeOffsets.end()); |
842 | int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2]; |
843 | // Only let other nodes change our time by so much |
844 | if (abs64(nMedian) < 70 * 60) |
845 | { |
846 | nTimeOffset = nMedian; |
847 | } |
848 | else |
849 | { |
850 | nTimeOffset = 0; |
851 | |
852 | static bool fDone; |
853 | if (!fDone) |
854 | { |
855 | // If nobody has a time different than ours but within 5 minutes of ours, give a warning |
856 | bool fMatch = false; |
857 | BOOST_FOREACH(int64 nOffset, vTimeOffsets) |
858 | if (nOffset != 0 && abs64(nOffset) < 5 * 60) |
859 | fMatch = true; |
860 | |
861 | if (!fMatch) |
862 | { |
863 | fDone = true; |
864 | string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly."); |
865 | strMiscWarning = strMessage; |
866 | printf("*** %s\n", strMessage.c_str()); |
867 | boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1)); |
868 | } |
869 | } |
870 | } |
871 | BOOST_FOREACH(int64 n, vTimeOffsets) |
872 | printf("%+"PRI64d" ", n); |
873 | printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60); |
874 | } |
875 | } |
876 | |
877 | |
878 | |
879 | |
880 | |
881 | |
882 | |
883 | |
884 | |
885 | string FormatVersion(int nVersion) |
886 | { |
887 | if (nVersion%100 == 0) |
888 | return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100); |
889 | else |
890 | return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100); |
891 | } |
892 | |
893 | string FormatFullVersion() |
894 | { |
895 | string s = FormatVersion(VERSION); |
896 | return s; |
897 | } |
898 | |
899 | std::string FormatSubVersion(const std::string& name, int nClientVersion) |
900 | { |
901 | std::ostringstream ss; |
902 | ss << "/"; |
903 | ss << name << ":" << FormatVersion(nClientVersion); |
904 | ss << "/"; |
905 | return ss.str(); |
906 | } |
907 | |
908 | |
909 | |
910 | #ifdef DEBUG_LOCKORDER |
911 | // |
912 | // Early deadlock detection. |
913 | // Problem being solved: |
914 | // Thread 1 locks A, then B, then C |
915 | // Thread 2 locks D, then C, then A |
916 | // --> may result in deadlock between the two threads, depending on when they run. |
917 | // Solution implemented here: |
918 | // Keep track of pairs of locks: (A before B), (A before C), etc. |
919 | // Complain if any thread trys to lock in a different order. |
920 | // |
921 | |
922 | struct CLockLocation |
923 | { |
924 | CLockLocation(const char* pszName, const char* pszFile, int nLine) |
925 | { |
926 | mutexName = pszName; |
927 | sourceFile = pszFile; |
928 | sourceLine = nLine; |
929 | } |
930 | |
931 | std::string ToString() const |
932 | { |
933 | return mutexName+" "+sourceFile+":"+itostr(sourceLine); |
934 | } |
935 | |
936 | private: |
937 | std::string mutexName; |
938 | std::string sourceFile; |
939 | int sourceLine; |
940 | }; |
941 | |
942 | typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack; |
943 | |
944 | static boost::interprocess::interprocess_mutex dd_mutex; |
945 | static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders; |
946 | static boost::thread_specific_ptr<LockStack> lockstack; |
947 | |
948 | |
949 | static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2) |
950 | { |
951 | printf("POTENTIAL DEADLOCK DETECTED\n"); |
952 | printf("Previous lock order was:\n"); |
953 | BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2) |
954 | { |
955 | if (i.first == mismatch.first) printf(" (1)"); |
956 | if (i.first == mismatch.second) printf(" (2)"); |
957 | printf(" %s\n", i.second.ToString().c_str()); |
958 | } |
959 | printf("Current lock order is:\n"); |
960 | BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1) |
961 | { |
962 | if (i.first == mismatch.first) printf(" (1)"); |
963 | if (i.first == mismatch.second) printf(" (2)"); |
964 | printf(" %s\n", i.second.ToString().c_str()); |
965 | } |
966 | } |
967 | |
968 | static void push_lock(CCriticalSection* c, const CLockLocation& locklocation) |
969 | { |
970 | bool fOrderOK = true; |
971 | if (lockstack.get() == NULL) |
972 | lockstack.reset(new LockStack); |
973 | |
974 | if (fDebug) printf("Locking: %s\n", locklocation.ToString().c_str()); |
975 | dd_mutex.lock(); |
976 | |
977 | (*lockstack).push_back(std::make_pair(c, locklocation)); |
978 | |
979 | BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack)) |
980 | { |
981 | if (i.first == c) break; |
982 | |
983 | std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c); |
984 | if (lockorders.count(p1)) |
985 | continue; |
986 | lockorders[p1] = (*lockstack); |
987 | |
988 | std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first); |
989 | if (lockorders.count(p2)) |
990 | { |
991 | potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); |
992 | break; |
993 | } |
994 | } |
995 | dd_mutex.unlock(); |
996 | } |
997 | |
998 | static void pop_lock() |
999 | { |
1000 | if (fDebug) |
1001 | { |
1002 | const CLockLocation& locklocation = (*lockstack).rbegin()->second; |
1003 | printf("Unlocked: %s\n", locklocation.ToString().c_str()); |
1004 | } |
1005 | dd_mutex.lock(); |
1006 | (*lockstack).pop_back(); |
1007 | dd_mutex.unlock(); |
1008 | } |
1009 | |
1010 | void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) |
1011 | { |
1012 | push_lock(this, CLockLocation(pszName, pszFile, nLine)); |
1013 | mutex.lock(); |
1014 | } |
1015 | void CCriticalSection::Leave() |
1016 | { |
1017 | mutex.unlock(); |
1018 | pop_lock(); |
1019 | } |
1020 | bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine) |
1021 | { |
1022 | push_lock(this, CLockLocation(pszName, pszFile, nLine)); |
1023 | bool result = mutex.try_lock(); |
1024 | if (!result) pop_lock(); |
1025 | return result; |
1026 | } |
1027 | |
1028 | #else |
1029 | |
1030 | void CCriticalSection::Enter(const char*, const char*, int) |
1031 | { |
1032 | mutex.lock(); |
1033 | } |
1034 | |
1035 | void CCriticalSection::Leave() |
1036 | { |
1037 | mutex.unlock(); |
1038 | } |
1039 | |
1040 | bool CCriticalSection::TryEnter(const char*, const char*, int) |
1041 | { |
1042 | bool result = mutex.try_lock(); |
1043 | return result; |
1044 | } |
1045 | |
1046 | #endif /* DEBUG_LOCKORDER */ |