upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/randomx_pow.cpp
blob: 17bf455523834bec8063bf24f6ef6b8b53dda0e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (c) 2026 Bitflash developers
// Distributed under the MIT/X11 software license.
//
// RandomX PoW implementation. See randomx_pow.h.

#include "headers.h"
#include <randomx.h>
#include <thread>
#include <vector>

// Fixed key (seed) that determines the RandomX cache/dataset. Keeping it
// constant avoids per-epoch "reseed" logic; for the CPU+RAM fairness goal
// this is sufficient (RandomX already neutralizes GPU/ASIC by design).
static const char* RANDOMX_KEY = "Bitflash/RandomX/v1/one-cpu-one-vote";

static randomx_flags   g_flags   = RANDOMX_FLAG_DEFAULT;
static randomx_cache*  g_cache   = NULL;
static randomx_dataset* g_dataset = NULL;
static randomx_vm*     g_vmVerify = NULL;
static CCriticalSection g_csVerify;
static bool            g_fInit    = false;
static bool            g_fFast    = false;


bool RandomXInit()
{
    if (g_fInit)
        return true;

    // Detect the best flags for this CPU (JIT, hardware AES, Argon2).
    g_flags = randomx_get_flags();

    g_cache = randomx_alloc_cache(g_flags);
    if (!g_cache)
    {
        // Try without JIT as a fallback
        g_flags = RANDOMX_FLAG_DEFAULT;
        g_cache = randomx_alloc_cache(g_flags);
        if (!g_cache)
            return error("RandomX: failed to allocate cache (256 MB)");
    }
    randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY));

    // Verification VM in light mode (cache only)
    g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL);
    if (!g_vmVerify)
        return error("RandomX: failed to create verification VM");

    g_fInit = true;
    printf("RandomX: initialized (cache 256 MB, flags=%d)\n", (int)g_flags);
    return true;
}


bool RandomXInitDataset(int nThreads)
{
    if (!g_fInit && !RandomXInit())
        return false;
    if (g_fFast)
        return true;

    randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM);
    g_dataset = randomx_alloc_dataset(fastFlags);
    if (!g_dataset)
    {
        printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n");
        return false;
    }

    unsigned long total = randomx_dataset_item_count();
    if (nThreads < 1) nThreads = 1;
    printf("RandomX: initializing ~2 GB dataset with %d threads...\n", nThreads);

    std::vector<std::thread> workers;
    unsigned long per = total / nThreads;
    for (int i = 0; i < nThreads; i++)
    {
        unsigned long start = i * per;
        unsigned long count = (i == nThreads - 1) ? (total - start) : per;
        workers.emplace_back([start, count]() {
            randomx_init_dataset(g_dataset, g_cache, start, count);
        });
    }
    for (auto& w : workers) w.join();

    g_fFast = true;
    printf("RandomX: dataset ready (fast mode active)\n");
    return true;
}


bool RandomXFastReady()
{
    return g_fFast;
}


uint256 RandomXPoWHash(const void* pHeader, size_t nSize)
{
    uint256 result = 0;
    if (!g_fInit && !RandomXInit())
        return result;
    CRITICAL_BLOCK(g_csVerify)
    {
        unsigned char hash[RANDOMX_HASH_SIZE];
        randomx_calculate_hash(g_vmVerify, pHeader, nSize, hash);
        memcpy(&result, hash, RANDOMX_HASH_SIZE);
    }
    return result;
}


void* RandomXCreateMinerVM()
{
    if (!g_fInit && !RandomXInit())
        return NULL;
    if (g_fFast && g_dataset)
    {
        randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM);
        return randomx_create_vm(fastFlags, NULL, g_dataset);
    }
    // Light mode: own VM sharing the cache
    return randomx_create_vm(g_flags, g_cache, NULL);
}


void RandomXDestroyMinerVM(void* vm)
{
    if (vm)
        randomx_destroy_vm((randomx_vm*)vm);
}


uint256 RandomXHashWithVM(void* vm, const void* pHeader, size_t nSize)
{
    uint256 result = 0;
    if (!vm)
        return result;
    unsigned char hash[RANDOMX_HASH_SIZE];
    randomx_calculate_hash((randomx_vm*)vm, pHeader, nSize, hash);
    memcpy(&result, hash, RANDOMX_HASH_SIZE);
    return result;
}