upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/randomx_pow.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-05 05:08:30 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-05 05:08:30 +0000
commit66e0b9158d050c46b1ff2509faeee3f4573cac1c (patch)
tree7e9132aa871fdc01cb95268d2f5ea3bb11853ddf /src/randomx_pow.cpp
parent36201d2795b7b49beb1a837b0252134096beb64d (diff)
parent17741d9cf4c762ea03dc83e8aae6a176e5f338b0 (diff)
Merge upstream/main into the fork
Brings the nine commits that are actually the latest on our lineage: isolated testnet parameters and genesis, optional 2 MB large pages for RandomX, and five README changes. This is what "up to date" means here -- not the 1.2.2x tags, which carry higher version numbers but were cut 2026-07-30, three weeks before the line we ship, and which upstream/main does not contain. Three conflicts, all resolved toward upstream's structure while keeping what this fork knows: main.cpp -- upstream moved genesis construction into BuildGenesisBlock() so mainnet and the new testnet can share it. Verified byte-for-byte before taking it: MAINNET_GENESIS_TIMESTAMP, _TIME (1753315200), _NONCE (3141), _HASH, _MERKLE, the scriptPubKey, nBits and nVersion all equal what this tree built inline. The mainnet genesis hash is unchanged and the asserts still guard it. Kept our warning about never editing those inputs, and kept our note that 1753315200 is 2025-07-24, not 2026 -- upstream's comment on that constant states the wrong year. net.h -- DEFAULT_PORT = htons(8433) becomes MAINNET_PORT/TESTNET_PORT in host order. Nothing is lost: net.cpp's GetDefaultPort() applies htons() itself and is what every caller uses, so the value reaching a sockaddr is unchanged and mainnet stays on 8433. selftest.cpp -- the known-tests string had diverged in both directions. Took the union: upstream's network-params alongside our payout-ledger, rather than dropping either. Gates: 15/15 selftests (our 14 plus upstream's network-params), consensus constants unchanged against e4f898c except the pre-existing MAX_BLOCK_SIZE_GEN, mainnet genesis intact, compactblock's 17 checks still pass, money-log check ok, GNU_STACK RW.
Diffstat (limited to 'src/randomx_pow.cpp')
-rw-r--r--src/randomx_pow.cpp117
1 files changed, 106 insertions, 11 deletions
diff --git a/src/randomx_pow.cpp b/src/randomx_pow.cpp
index 9c59364..a509543 100644
--- a/src/randomx_pow.cpp
+++ b/src/randomx_pow.cpp
@@ -24,6 +24,50 @@ static std::mutex g_csInit;
24static bool g_fInit = false; 24static bool g_fInit = false;
25static bool g_fFast = false; 25static bool g_fFast = false;
26 26
27// RandomX reads a 256 MB cache, a 2 GB dataset and a 2 MB scratchpad per VM
28// at random, so most reads miss the TLB on 4 KB pages. 2 MB pages recover
29// roughly a tenth of the hash rate.
30//
31// The pool must be reserved first (vm.nr_hugepages), and RandomX returns NULL
32// instead of falling back, so each allocation below retries without the flag.
33bool fRandomXLargePages = true; // cleared by -nolargepages
34static bool g_fLargeCache = false;
35static bool g_fLargeDataset = false;
36static bool g_fLargeAny = false;
37
38// How to reserve the large-page pool, for the hint printed when a large-page
39// allocation falls back to normal pages. The mechanism is OS-specific.
40static const char* LargePagesHint()
41{
42#ifdef _WIN32
43 return "enable the \"Lock pages in memory\" privilege and run elevated";
44#else
45 return "reserve them with: sysctl vm.nr_hugepages=1280";
46#endif
47}
48
49static randomx_flags WithLargePages(randomx_flags f)
50{
51 return (randomx_flags)(f | RANDOMX_FLAG_LARGE_PAGES);
52}
53
54// Ask for a cache in large pages, then plain pages. Sets fLargeOut to say
55// which one answered.
56static randomx_cache* AllocCache(randomx_flags flags, bool& fLargeOut)
57{
58 fLargeOut = false;
59 if (fRandomXLargePages)
60 {
61 randomx_cache* c = randomx_alloc_cache(WithLargePages(flags));
62 if (c)
63 {
64 fLargeOut = true;
65 return c;
66 }
67 }
68 return randomx_alloc_cache(flags);
69}
70
27 71
28bool RandomXInit() 72bool RandomXInit()
29{ 73{
@@ -37,28 +81,56 @@ bool RandomXInit()
37 // Detect the best flags for this CPU (JIT, hardware AES, Argon2). 81 // Detect the best flags for this CPU (JIT, hardware AES, Argon2).
38 g_flags = randomx_get_flags(); 82 g_flags = randomx_get_flags();
39 83
40 g_cache = randomx_alloc_cache(g_flags); 84 g_cache = AllocCache(g_flags, g_fLargeCache);
41 if (!g_cache) 85 if (!g_cache)
42 { 86 {
43 // Try without JIT as a fallback 87 // Try without JIT as a fallback
44 g_flags = RANDOMX_FLAG_DEFAULT; 88 g_flags = RANDOMX_FLAG_DEFAULT;
45 g_cache = randomx_alloc_cache(g_flags); 89 g_cache = AllocCache(g_flags, g_fLargeCache);
46 if (!g_cache) 90 if (!g_cache)
47 return error("RandomX: failed to allocate cache (256 MB)"); 91 return error("RandomX: failed to allocate cache (256 MB)");
48 } 92 }
49 randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY)); 93 randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY));
50 94
51 // Verification VM in light mode (cache only) 95 // Verification VM in light mode (cache only). The scratchpad is only 2 MB
52 g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL); 96 // and this VM is created once, but it hashes every block the node ever
97 // validates, so it gets the same treatment.
98 bool fLargeVerify = false;
99 if (fRandomXLargePages)
100 {
101 g_vmVerify = randomx_create_vm(WithLargePages(g_flags), g_cache, NULL);
102 fLargeVerify = (g_vmVerify != NULL);
103 }
104 if (!g_vmVerify)
105 g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL);
53 if (!g_vmVerify) 106 if (!g_vmVerify)
54 return error("RandomX: failed to create verification VM"); 107 return error("RandomX: failed to create verification VM");
55 108
109 g_fLargeAny = g_fLargeCache || fLargeVerify;
56 g_fInit = true; 110 g_fInit = true;
57 printf("RandomX: initialized (cache 256 MB, flags=%d)\n", (int)g_flags); 111 printf("RandomX: initialized (cache 256 MB, flags=%d, large pages: %s)\n",
112 (int)g_flags, RandomXLargePagesStatus());
113 if (fRandomXLargePages && !g_fLargeCache)
114 printf("RandomX: large pages unavailable for the cache; %s "
115 "for about 10%% more hash rate\n", LargePagesHint());
58 return true; 116 return true;
59} 117}
60 118
61 119
120const char* RandomXLargePagesStatus()
121{
122 if (!fRandomXLargePages)
123 return "off (-nolargepages)";
124 if (g_fLargeCache && g_fLargeDataset)
125 return "cache + dataset";
126 if (g_fLargeCache)
127 return "cache only";
128 if (g_fLargeDataset)
129 return "dataset only";
130 return g_fLargeAny ? "scratchpad only" : "unavailable";
131}
132
133
62// One dataset, once, no matter how many miners ask for it. 134// One dataset, once, no matter how many miners ask for it.
63// 135//
64// Every miner thread calls this at startup. The g_fFast guard below is only 136// Every miner thread calls this at startup. The g_fFast guard below is only
@@ -88,8 +160,18 @@ bool RandomXInitDataset(int nThreads)
88 if (g_fFast) 160 if (g_fFast)
89 return true; 161 return true;
90 162
91 randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); 163 // Only RANDOMX_FLAG_LARGE_PAGES means anything to randomx_alloc_dataset;
92 g_dataset = randomx_alloc_dataset(fastFlags); 164 // the rest of g_flags belongs to the VMs that read it.
165 if (fRandomXLargePages)
166 {
167 g_dataset = randomx_alloc_dataset(WithLargePages(RANDOMX_FLAG_DEFAULT));
168 g_fLargeDataset = (g_dataset != NULL);
169 if (!g_dataset)
170 printf("RandomX: large pages unavailable for the 2 GB dataset; %s "
171 "for about 10%% more hash rate\n", LargePagesHint());
172 }
173 if (!g_dataset)
174 g_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
93 if (!g_dataset) 175 if (!g_dataset)
94 { 176 {
95 printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n"); 177 printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n");
@@ -158,13 +240,26 @@ void* RandomXCreateMinerVM()
158{ 240{
159 if (!g_fInit && !RandomXInit()) 241 if (!g_fInit && !RandomXInit())
160 return NULL; 242 return NULL;
243
244 randomx_flags flags = g_flags;
245 randomx_cache* cache = g_cache;
246 randomx_dataset* dataset = NULL;
161 if (g_fFast && g_dataset) 247 if (g_fFast && g_dataset)
162 { 248 {
163 randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); 249 flags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM);
164 return randomx_create_vm(fastFlags, NULL, g_dataset); 250 cache = NULL;
251 dataset = g_dataset;
252 }
253
254 // Each thread gets its own 2 MB scratchpad, so the large-page pool can run
255 // dry partway through a fleet of miners. Threads that miss out still run.
256 if (fRandomXLargePages)
257 {
258 randomx_vm* vm = randomx_create_vm(WithLargePages(flags), cache, dataset);
259 if (vm)
260 return vm;
165 } 261 }
166 // Light mode: own VM sharing the cache 262 return randomx_create_vm(flags, cache, dataset);
167 return randomx_create_vm(g_flags, g_cache, NULL);
168} 263}
169 264
170 265