upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/util.h
diff options
context:
space:
mode:
authorbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
committerbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
commit5ce650382352c1503f40abf08129ada69402af55 (patch)
tree6a18198901f1e2c4933f1ac53c9365eec512bf63 /src/util.h
parentf34113291da7e5e3dc7d2468d4f9c212c05c584b (diff)
public commit
Diffstat (limited to 'src/util.h')
-rw-r--r--src/util.h557
1 files changed, 557 insertions, 0 deletions
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..d95d3ae
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,557 @@
1// Copyright (c) 2009 Satoshi Nakamoto
2// Distributed under the MIT/X11 software license, see the accompanying
3// file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5
6// For abi::__forced_unwind, which CATCH_PRINT_EXCEPTION below must let past.
7#ifndef _WIN32
8#include <cxxabi.h>
9#endif
10
11#if defined(_MSC_VER) || defined(__BORLANDC__)
12typedef __int64 int64;
13typedef unsigned __int64 uint64;
14#else
15typedef long long int64;
16typedef unsigned long long uint64;
17#endif
18#if defined(_MSC_VER) && _MSC_VER < 1300
19#define for if (false) ; else for
20#endif
21
22// MinGW already provides __forceinline for MSVC compatibility, so defining it
23// unconditionally warned ten times per build once -w was removed.
24#if !defined(_MSC_VER) && !defined(__forceinline)
25#define __forceinline inline
26#endif
27
28#define foreach BOOST_FOREACH
29#define loop for (;;)
30#define BEGIN(a) ((char*)&(a))
31#define END(a) ((char*)&((&(a))[1]))
32#define UBEGIN(a) ((unsigned char*)&(a))
33#define UEND(a) ((unsigned char*)&((&(a))[1]))
34#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
35
36// Route printf to debug.log (and the console on non-Windows) everywhere.
37// (Previously gated on `defined(_WINDOWS) || !defined(_WIN32)` -- but
38// _WINDOWS is only ever defined by the legacy, unused makefile.vc build;
39// the real Windows build (makefile.mingw) never defines it, so on actual
40// Windows this condition was always false and debug.log was never written.
41// OutputDebugStringF() is already platform-safe internally: it always
42// writes debug.log, and only echoes to the console when not on Windows.)
43#define printf OutputDebugStringF
44
45#ifdef snprintf
46#undef snprintf
47#endif
48#define snprintf my_snprintf
49
50// One definition for every target. The MSVCRT branch that used to sit here
51// produced "I64d", which is the specifier that segfaults on glibc (issue #5) --
52// and it was pointless besides: this build targets UCRT, which accepts the C99
53// forms, and the rest of the tree already prints int64 with %lld on Windows.
54// Keeping one spelling everywhere is also what lets the format attributes below
55// use a single archetype, so a bad specifier fails the build on both platforms.
56#ifndef PRId64
57#define PRId64 "lld"
58#define PRIu64 "llu"
59#define PRIx64 "llx"
60#endif
61
62// This is needed because the foreach macro can't get over the comma in pair<t1, t2>
63#define PAIRTYPE(t1, t2) pair<t1, t2>
64
65// Used to bypass the rule against non-const reference to temporary
66// where it makes sense with wrappers such as CFlatData or CTxDB
67template<typename T>
68inline T& REF(const T& val)
69{
70 return (T&)val;
71}
72
73
74
75
76
77
78
79
80
81extern bool fDebug;
82
83// ---------------------------------------------------------------------------
84// Categorized, burst-collapsing logging
85//
86// Plain printf() (routed to OutputDebugStringF below) writes every call
87// unfiltered to debug.log. That's fine for one-off events, but a loop that
88// logs once per item -- once per discovered peer, once per connect attempt,
89// once per share -- turns debug.log into a wall of near-identical lines that
90// differ only by an address, while the line that actually explains a stuck
91// flow ("Stratum: no job available for ...") scrolls off screen under the
92// noise. LogPrint() is a drop-in replacement for printf() that fixes both
93// problems without touching call sites' formatting:
94//
95// 1. Category tag: every call names the subsystem it belongs to ("pool",
96// "worker", "payout", "net", "nostr", ...). LogAcceptsCategory()
97// controls what's written (see util.cpp); the pool/worker/payout flow
98// the person actually needs visibility into is on by default.
99// 2. Burst collapse: repeated LogPrint() calls from the *same source line*
100// only emit one line per DEDUP_WINDOW_SECS; if more calls land inside
101// that window they're counted instead of reprinted, and the count is
102// flushed as a single "(xN similar in Ws)" line the moment the window
103// rolls over. A loop discovering 500 peers by address now produces a
104// small, bounded number of lines instead of 500 -- log growth is capped
105// by elapsed time, not by how many similar events happen to fire.
106// ---------------------------------------------------------------------------
107bool LogAcceptsCategory(const char* category);
108void LogPrintDedup(const char* category, const char* file, int line, const std::string& msg);
109#define LogPrint(category, ...) \
110 do { if (LogAcceptsCategory(category)) LogPrintDedup((category), __FILE__, __LINE__, strprintf(__VA_ARGS__)); } while (0)
111
112// Every format string in this project goes through one of the four functions
113// below -- `printf` itself is remapped to OutputDebugStringF just above, and
114// snprintf to my_snprintf. None of them carried a format attribute, and GCC
115// only checks format strings for functions it knows are printf-like, so
116// -Wformat had nothing to inspect and the whole tree was unchecked. That is
117// how `%I64d` (MSVC-only, and a segfault on glibc) survived in
118// CTxOut::ToString until it crashed a node mid-sync -- see issue #5.
119//
120// gnu_printf on both platforms, deliberately. MinGW's other option, ms_printf,
121// models the legacy msvcrt: it rejects %zu, which this tree uses and UCRT
122// supports, and it accepts %I64d, which is the specifier that crashes on glibc.
123// It would give false positives where the code is right and stay silent where it
124// is dangerous. gnu_printf describes UCRT's C99 behaviour accurately, so one
125// archetype covers both builds and a bad specifier fails either one.
126#if defined(__GNUC__)
127#define BF_FORMAT(fmt, args) __attribute__((format(gnu_printf, fmt, args)))
128#else
129#define BF_FORMAT(fmt, args)
130#endif
131
132void RandAddSeed(bool fPerfmon=false);
133int my_snprintf(char* buffer, size_t limit, const char* format, ...) BF_FORMAT(3, 4);
134string strprintf(const char* format, ...) BF_FORMAT(1, 2);
135bool error(const char* format, ...) BF_FORMAT(1, 2);
136void PrintException(std::exception* pex, const char* pszThread);
137void ParseString(const string& str, char c, vector<string>& v);
138string FormatMoney(int64 n, bool fPlus=false);
139bool ParseMoney(const char* pszIn, int64& nRet);
140bool FileExists(const char* psz);
141int GetFilesize(FILE* file);
142uint64 GetRand(uint64 nMax);
143int64 GetTime();
144int64 GetAdjustedTime();
145void AddTimeData(unsigned int ip, int64 nTime);
146
147
148
149
150
151
152
153
154
155
156
157
158// Wrapper to automatically initialize critical section
159// Could use wxCriticalSection for portability, but it doesn't support TryEnterCriticalSection
160class CCriticalSection
161{
162protected:
163 CRITICAL_SECTION cs;
164public:
165 char* pszFile;
166 int nLine;
167 explicit CCriticalSection() { InitializeCriticalSection(&cs); }
168 ~CCriticalSection() { DeleteCriticalSection(&cs); }
169 void Enter() { EnterCriticalSection(&cs); }
170 void Leave() { LeaveCriticalSection(&cs); }
171 bool TryEnter() { return TryEnterCriticalSection(&cs); }
172 CRITICAL_SECTION* operator&() { return &cs; }
173};
174
175// Automatically leave critical section when leaving block, needed for exception safety
176class CCriticalBlock
177{
178protected:
179 CRITICAL_SECTION* pcs;
180public:
181 CCriticalBlock(CRITICAL_SECTION& csIn) { pcs = &csIn; EnterCriticalSection(pcs); }
182 CCriticalBlock(CCriticalSection& csIn) { pcs = &csIn; EnterCriticalSection(pcs); }
183 ~CCriticalBlock() { LeaveCriticalSection(pcs); }
184};
185
186// WARNING: This will catch continue and break!
187// break is caught with an assertion, but there's no way to detect continue.
188// I'd rather be careful than suffer the other more error prone syntax.
189// The compiler will optimise away all this loop junk.
190#define CRITICAL_BLOCK(cs) \
191 for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
192 for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
193
194class CTryCriticalBlock
195{
196protected:
197 CRITICAL_SECTION* pcs;
198public:
199 CTryCriticalBlock(CRITICAL_SECTION& csIn) { pcs = (TryEnterCriticalSection(&csIn) ? &csIn : NULL); }
200 CTryCriticalBlock(CCriticalSection& csIn) { pcs = (TryEnterCriticalSection(&csIn) ? &csIn : NULL); }
201 ~CTryCriticalBlock() { if (pcs) LeaveCriticalSection(pcs); }
202 bool Entered() { return pcs != NULL; }
203};
204
205#define TRY_CRITICAL_BLOCK(cs) \
206 for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
207 for (CTryCriticalBlock criticalblock(cs); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()) && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
208
209
210
211
212
213
214
215
216
217
218
219
220inline string i64tostr(int64 n)
221{
222 return strprintf("%" PRId64, n);
223}
224
225inline string itostr(int n)
226{
227 return strprintf("%d", n);
228}
229
230inline int64 atoi64(const char* psz)
231{
232#ifdef _MSC_VER
233 return _atoi64(psz);
234#else
235 return strtoll(psz, NULL, 10);
236#endif
237}
238
239inline int64 atoi64(const string& str)
240{
241#ifdef _MSC_VER
242 return _atoi64(str.c_str());
243#else
244 return strtoll(str.c_str(), NULL, 10);
245#endif
246}
247
248inline int atoi(const string& str)
249{
250 return atoi(str.c_str());
251}
252
253inline int roundint(double d)
254{
255 return (int)(d > 0 ? d + 0.5 : d - 0.5);
256}
257
258template<typename T>
259string HexStr(const T itbegin, const T itend, bool fSpaces=true)
260{
261 const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
262 const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
263 string str;
264 for (const unsigned char* p = pbegin; p != pend; p++)
265 str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p);
266 return str;
267}
268
269template<typename T>
270string HexNumStr(const T itbegin, const T itend, bool f0x=true)
271{
272 const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
273 const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
274 string str = (f0x ? "0x" : "");
275 for (const unsigned char* p = pend-1; p >= pbegin; p--)
276 str += strprintf("%02X", *p);
277 return str;
278}
279
280template<typename T>
281void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true)
282{
283 printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
284}
285
286
287
288
289
290
291
292
293// Forward declaration -- defined in main.cpp
294string GetAppDir();
295
296// Give a command-line operation somewhere to print.
297//
298// The Windows binary is linked -mwindows and starts with no console, so stdout
299// goes nowhere even when it was launched from a terminal. Commands that report
300// to the person who typed them -- the self-tests, the wallet phrase commands --
301// call this first.
302//
303// Only when there is nowhere for stdout to go already: if the caller redirected
304// it to a file or a pipe, that handle is inherited and works, and reopening it
305// on CONOUT$ would take the output away from the file and put it on the screen.
306inline void AttachTerminal()
307{
308#ifdef _WIN32
309 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
310 if (hOut != NULL && hOut != INVALID_HANDLE_VALUE)
311 return;
312 if (AttachConsole(ATTACH_PARENT_PROCESS))
313 {
314 // Return values ignored on purpose: if the reopen fails there is
315 // nowhere left to report it, and the exit status still carries the
316 // result.
317 freopen("CONOUT$", "w", stdout);
318 freopen("CONOUT$", "w", stderr);
319 }
320#endif
321}
322
323inline int OutputDebugStringF(const char* pszFormat, ...) BF_FORMAT(1, 2);
324
325inline int OutputDebugStringF(const char* pszFormat, ...)
326{
327#if 1 // debug.log always enabled
328 // Write to data directory so it's always findable.
329 //
330 // Path resolution and the write are both under the lock, because neither
331 // used to be under anything. strDebugFile was filled in lazily inside an
332 // `if (empty())`, so one thread could read the path while another was
333 // still assigning to it -- and at startup three threads log within
334 // milliseconds of each other. When that raced, fopen got a torn path,
335 // returned NULL, and the `if (fileout)` below dropped the line silently.
336 // Measured before this change: unconditional first-statement printfs in
337 // ThreadBtfAccept, ThreadNostrSeed and the cached-peer thread reached the
338 // file in only 4/6, 5/6 and 2/6 of runs respectively. Concluding a thread
339 // never ran because its line was absent was not sound, and the lock also
340 // stops several threads calling fopen on the same file at once.
341 static CCriticalSection cs_debugFile;
342 CRITICAL_BLOCK(cs_debugFile)
343 {
344 static string strDebugFile;
345 if (strDebugFile.empty()) {
346 string dir = GetAppDir();
347 if (!dir.empty())
348 strDebugFile = dir +
349#ifdef _WIN32
350 "\\"
351#else
352 "/"
353#endif
354 + "debug.log";
355 else
356 strDebugFile = "debug.log";
357 }
358 FILE* fileout = fopen(strDebugFile.c_str(), "a");
359 if (fileout)
360 {
361 va_list arg_ptr;
362 va_start(arg_ptr, pszFormat);
363 vfprintf(fileout, pszFormat, arg_ptr);
364 va_end(arg_ptr);
365 fclose(fileout);
366 }
367 }
368
369#ifndef _WIN32
370 // Headless build: also echo to the console (the Windows path below returns
371 // early before reaching the console print, which is fine for the GUI app).
372 {
373 va_list arg_ptr;
374 va_start(arg_ptr, pszFormat);
375 vprintf(pszFormat, arg_ptr);
376 va_end(arg_ptr);
377 fflush(stdout);
378 }
379#endif
380
381 // accumulate a line at a time
382 static CCriticalSection cs_OutputDebugStringF;
383 CRITICAL_BLOCK(cs_OutputDebugStringF)
384 {
385 static char pszBuffer[50000];
386 static char* pend;
387 if (pend == NULL)
388 pend = pszBuffer;
389 va_list arg_ptr;
390 va_start(arg_ptr, pszFormat);
391 int limit = END(pszBuffer) - pend - 2;
392 int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
393 va_end(arg_ptr);
394 if (ret < 0 || ret >= limit)
395 {
396 pend = END(pszBuffer) - 2;
397 *pend++ = '\n';
398 }
399 else
400 pend += ret;
401 *pend = '\0';
402 char* p1 = pszBuffer;
403 char* p2;
404 while (p2 = strchr(p1, '\n'))
405 {
406 p2++;
407 char c = *p2;
408 *p2 = '\0';
409 OutputDebugStringA(p1);
410 *p2 = c;
411 p1 = p2;
412 }
413 if (p1 != pszBuffer)
414 memmove(pszBuffer, p1, pend - p1 + 1);
415 pend -= (p1 - pszBuffer);
416 return ret;
417 }
418#endif
419
420 va_list arg_ptr;
421 va_start(arg_ptr, pszFormat);
422 vprintf(pszFormat, arg_ptr);
423 va_end(arg_ptr);
424 return 0;
425}
426
427
428
429
430
431
432
433
434
435inline void heapchk()
436{
437 if (_heapchk() != _HEAPOK)
438 DebugBreak();
439}
440
441// Randomize the stack to help protect against buffer overrun exploits
442#define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \
443 { \
444 static char nLoops; \
445 if (nLoops <= 0) \
446 nLoops = GetRand(50) + 1; \
447 if (nLoops-- > 1) \
448 { \
449 ThreadFn; \
450 return; \
451 } \
452 }
453
454// The forced-unwind arm has to come first, and it has to rethrow.
455//
456// On POSIX, _endthread() is pthread_exit(), and glibc implements that by
457// throwing abi::__forced_unwind through the stack. It is not a real exception
458// and catching it without rethrowing is a fatal error by contract: glibc
459// notices and calls abort().
460//
461// The bare catch(...) below did exactly that. Every shutdown on Linux died with
462//
463// UNKNOWN EXCEPTION bitflash-node in ThreadSocketHandler()
464// FATAL: exception not rethrown
465//
466// which looked like nothing worse than an ugly exit, and was not: the process
467// aborted partway through shutting down, so nothing after StopNode() ran. See
468// main_gui.cpp, where DBFlush(true) is now called -- it could never have
469// worked while this abort stood in front of it. Windows is unaffected; there
470// _endthread() is the CRT's and unwinds nothing.
471#ifdef _WIN32
472#define CATCH_FORCED_UNWIND
473#else
474#define CATCH_FORCED_UNWIND \
475 catch (abi::__forced_unwind&) { \
476 throw; \
477 }
478#endif
479
480#define CATCH_PRINT_EXCEPTION(pszFn) \
481 CATCH_FORCED_UNWIND \
482 catch (std::exception& e) { \
483 PrintException(&e, (pszFn)); \
484 } catch (...) { \
485 PrintException(NULL, (pszFn)); \
486 }
487
488
489
490
491
492
493
494
495
496template<typename T1>
497inline uint256 Hash(const T1 pbegin, const T1 pend)
498{
499 uint256 hash1;
500 SHA256((unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
501 uint256 hash2;
502 SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
503 return hash2;
504}
505
506template<typename T1, typename T2>
507inline uint256 Hash(const T1 p1begin, const T1 p1end,
508 const T2 p2begin, const T2 p2end)
509{
510 uint256 hash1;
511 SHA256_CTX ctx;
512 SHA256_Init(&ctx);
513 SHA256_Update(&ctx, (unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]));
514 SHA256_Update(&ctx, (unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]));
515 SHA256_Final((unsigned char*)&hash1, &ctx);
516 uint256 hash2;
517 SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
518 return hash2;
519}
520
521template<typename T1, typename T2, typename T3>
522inline uint256 Hash(const T1 p1begin, const T1 p1end,
523 const T2 p2begin, const T2 p2end,
524 const T3 p3begin, const T3 p3end)
525{
526 uint256 hash1;
527 SHA256_CTX ctx;
528 SHA256_Init(&ctx);
529 SHA256_Update(&ctx, (unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]));
530 SHA256_Update(&ctx, (unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]));
531 SHA256_Update(&ctx, (unsigned char*)&p3begin[0], (p3end - p3begin) * sizeof(p3begin[0]));
532 SHA256_Final((unsigned char*)&hash1, &ctx);
533 uint256 hash2;
534 SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
535 return hash2;
536}
537
538template<typename T>
539uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=VERSION)
540{
541 // Most of the time is spent allocating and deallocating CDataStream's
542 // buffer. If this ever needs to be optimized further, make a CStaticStream
543 // class with its buffer on the stack.
544 CDataStream ss(nType, nVersion);
545 ss.reserve(10000);
546 ss << obj;
547 return Hash(ss.begin(), ss.end());
548}
549
550inline uint160 Hash160(const vector<unsigned char>& vch)
551{
552 uint256 hash1;
553 SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
554 uint160 hash2;
555 RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
556 return hash2;
557}