diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-05 05:08:30 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-05 05:08:30 +0000 |
| commit | 66e0b9158d050c46b1ff2509faeee3f4573cac1c (patch) | |
| tree | 7e9132aa871fdc01cb95268d2f5ea3bb11853ddf /src/randomx_pow.cpp | |
| parent | 36201d2795b7b49beb1a837b0252134096beb64d (diff) | |
| parent | 17741d9cf4c762ea03dc83e8aae6a176e5f338b0 (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.cpp | 117 |
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; | |||
| 24 | static bool g_fInit = false; | 24 | static bool g_fInit = false; |
| 25 | static bool g_fFast = false; | 25 | static 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. | ||
| 33 | bool fRandomXLargePages = true; // cleared by -nolargepages | ||
| 34 | static bool g_fLargeCache = false; | ||
| 35 | static bool g_fLargeDataset = false; | ||
| 36 | static 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. | ||
| 40 | static 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 | |||
| 49 | static 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. | ||
| 56 | static 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 | ||
| 28 | bool RandomXInit() | 72 | bool 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 | ||
| 120 | const 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 | ||