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:
Diffstat (limited to 'src/randomx_pow.cpp')
-rw-r--r--src/randomx_pow.cpp23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/randomx_pow.cpp b/src/randomx_pow.cpp
index 17bf455..d617ba2 100644
--- a/src/randomx_pow.cpp
+++ b/src/randomx_pow.cpp
@@ -7,6 +7,7 @@
7#include <randomx.h> 7#include <randomx.h>
8#include <thread> 8#include <thread>
9#include <vector> 9#include <vector>
10#include <mutex>
10 11
11// Fixed key (seed) that determines the RandomX cache/dataset. Keeping it 12// Fixed key (seed) that determines the RandomX cache/dataset. Keeping it
12// constant avoids per-epoch "reseed" logic; for the CPU+RAM fairness goal 13// constant avoids per-epoch "reseed" logic; for the CPU+RAM fairness goal
@@ -52,10 +53,32 @@ bool RandomXInit()
52} 53}
53 54
54 55
56// One dataset, once, no matter how many miners ask for it.
57//
58// Every miner thread calls this at startup. The g_fFast guard below is only
59// set at the very end, after the ~2 GB dataset has been filled, which takes
60// tens of seconds -- so without this lock all of them sail past the guard
61// together and each allocates its own dataset. Measured in production: a
62// 32-core machine logged "initializing ~2 GB dataset" 34 times and committed
63// 65 GB of private pages against a startup message promising 2142 MB.
64//
65// The waste was the mild half. g_dataset is assigned the moment the memory is
66// allocated, before it holds anything, so the last thread to allocate would
67// swing the pointer out from under the threads still filling their own. A
68// miner could then hash against a dataset another thread had not finished
69// writing, producing proof of work that no other node can reproduce.
70//
71// Holding the lock across the whole initialisation is deliberate: a thread
72// that arrives mid-init has nothing useful to do until the dataset exists,
73// and blocking is how it waits for exactly that.
74static std::mutex g_csDataset;
75
55bool RandomXInitDataset(int nThreads) 76bool RandomXInitDataset(int nThreads)
56{ 77{
57 if (!g_fInit && !RandomXInit()) 78 if (!g_fInit && !RandomXInit())
58 return false; 79 return false;
80
81 std::lock_guard<std::mutex> lock(g_csDataset);
59 if (g_fFast) 82 if (g_fFast)
60 return true; 83 return true;
61 84