upleb.uk

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

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