Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/BLOCK_HASHING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Block hashing

## Background

In Bitcoin, block IDs and Proof-of-Work (PoW) hashes are calculated the same way, which is why on-chain block IDs always start
with many 0s. However, in Monero, block IDs and PoW hashes are calculated using different hash functions and slightly different
inputs. This is because the hash functions used for PoW (CryptoNight and RandomX) are much slower to run than other
cryptographic hash functions, specifically Keccak256, which Monero uses for block IDs. By contrast, Bitcoin uses SHA-256 for
both block IDs and PoW. The reason that CryptoNight and RandomX were chosen for PoW in Monero is to protect against
application-specific integrated circuits (ASICs) from dominanting the network hashrate like in Bitcoin. In theory, this
would restore the principle of "1 CPU, 1 vote" outlined in the Satoshi whitepaper, and bring greater decentralization to the
Monero exosystem. This document aims to describe exactly how block IDs and PoW hashes are calculated in the Monero reference
codebase.

## CryptoNight epoch

To be reductive, the underlying design of Cryptonight is to 1) fill a 2MB buffer of memory using a memory-hard function, 2)
perform over a millon random reads on that buffer to permutate some state, and then 3) do a final hash on the state using
a random choice between four independent hash fuctions. There are 4 variants of CryptoNight: v0, v1, v2, and v4. This is the
data flow for how block hashing in the CryptoNight epoch (Monero fork versions v1-v11) is performed:

![CryptoNight data flow](resources/cryptonight-data-flow.png)

## RandomX epoch

Like, CryptoNight, RandomX also uses a memory hard function to fill a large space of memory called a "cache". However, this
space is 256MB, not 2MB. It can be further expanded to 2GB to trade memory usage for compute speed. Unlike CryptoNight's cache,
the RandomX cache is computed only once every 2048 blocks, not once per block. Monero uses a "seed" block ID of a previous block
in the chain to fill the memory space. And to make ASICs even harder, RandomX uses random instruction execution as well. This
is the data flow for how block hashing in the RandomX epoch (Monero fork versions v12-present) is performed:

![RandomX data flow](resources/randomx-data-flow.png)

## RandomX, with commitments, epoch

Because RandomX can be slow to run, especially while building the cache (nearly 1/2 a second on my machine), it inadvertantly
can introduce a Denial-of-Service (DoS) vector. For this reason, RandomX hash commitments can be added, so the PoW can be
partially verified using only Blake2B, a much lighter hash function. For simplicity's sake, we can also remove the number of
transactions in the block from the block hashing blob. This is the data flow for how block hashing works with these changes:

![RandomX commitment data flow](resources/randomx-commitment-data-flow.png)

The way that the hashes are calculated allows us to do partial PoW verification like so:

![Partial RandomX verification data flow](resources/partial-pow-verify-data-flow.png)

A node can be given simply the block header, block content hash, and intermediate PoW hash, and verify that some PoW was done
using only `randomx_calculate_commitment()` (Blake2B underneath). Passing this partial verification requires PoW to be done using
Blake2B up to the relevant difficulty. While doing so is much easier than doing the full RandomX PoW, it still requires
significant work. It is very important that we can calculate the block ID from the same information (or a subset thereof)
that we calculate PoW from, since each block header contains the previous block ID. Binding the block headers as such makes
faking intermediate PoW on chains of blocks exponentially harder the longer the chain is.
Binary file added docs/resources/cryptonight-data-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/resources/partial-pow-verify-data-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/resources/randomx-commitment-data-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/resources/randomx-data-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion external/randomx
Submodule randomx updated 79 files
+13 −14 .github/workflows/c-cpp.yml
+124 −4 CMakeLists.txt
+1 −1 doc/configuration.md
+9 −2 doc/design.md
+111 −0 doc/design_v2.md
+17 −7 doc/specs.md
+58 −1 src/aes_hash.cpp
+287 −0 src/aes_hash_rv64_vector.cpp
+35 −0 src/aes_hash_rv64_vector.hpp
+210 −0 src/aes_hash_rv64_zvkned.cpp
+35 −0 src/aes_hash_rv64_zvkned.hpp
+3 −1 src/asm/configuration.asm
+9 −7 src/asm/program_epilogue_linux.inc
+1 −1 src/asm/program_epilogue_store.inc
+20 −20 src/asm/program_epilogue_win64.inc
+2 −2 src/asm/program_loop_load.inc
+2 −2 src/asm/program_loop_store.inc
+30 −0 src/asm/program_loop_store_hard_aes.inc
+97 −0 src/asm/program_loop_store_soft_aes.inc
+19 −11 src/asm/program_prologue_linux.inc
+31 −25 src/asm/program_prologue_win64.inc
+8 −9 src/asm/program_read_dataset_sshash_fin.inc
+11 −12 src/asm/program_read_dataset_sshash_init.inc
+16 −0 src/asm/program_read_dataset_sshash_init_v2.inc
+16 −0 src/asm/program_read_dataset_v2.inc
+49 −0 src/asm/program_soft_aes_dec.inc
+49 −0 src/asm/program_soft_aes_enc.inc
+2 −2 src/assembly_generator_x86.cpp
+1 −1 src/assembly_generator_x86.hpp
+1 −1 src/bytecode_machine.cpp
+10 −7 src/bytecode_machine.hpp
+13 −4 src/common.hpp
+4 −1 src/configuration.h
+53 −1 src/cpu.cpp
+17 −10 src/cpu.hpp
+47 −0 src/cpu_rv64.S
+1 −1 src/dataset.hpp
+56 −0 src/intrin_portable.h
+1 −1 src/jit_compiler.hpp
+95 −9 src/jit_compiler_a64.cpp
+4 −2 src/jit_compiler_a64.hpp
+335 −10 src/jit_compiler_a64_static.S
+9 −0 src/jit_compiler_a64_static.hpp
+4 −2 src/jit_compiler_fallback.hpp
+209 −86 src/jit_compiler_rv64.cpp
+19 −6 src/jit_compiler_rv64.hpp
+18 −8 src/jit_compiler_rv64_static.S
+3 −1 src/jit_compiler_rv64_static.hpp
+919 −0 src/jit_compiler_rv64_vector.cpp
+47 −0 src/jit_compiler_rv64_vector.h
+1,089 −0 src/jit_compiler_rv64_vector_static.S
+79 −0 src/jit_compiler_rv64_vector_static.h
+134 −34 src/jit_compiler_x86.cpp
+8 −3 src/jit_compiler_x86.hpp
+36 −2 src/jit_compiler_x86_static.S
+42 −2 src/jit_compiler_x86_static.asm
+6 −0 src/jit_compiler_x86_static.hpp
+4 −4 src/program.hpp
+44 −25 src/randomx.cpp
+13 −2 src/randomx.h
+41 −40 src/soft_aes.cpp
+6 −0 src/soft_aes.h
+11 −3 src/tests/benchmark.cpp
+6 −5 src/tests/code-generator.cpp
+12 −0 src/tests/riscv64_vector.s
+11 −0 src/tests/riscv64_zicbop.s
+13 −0 src/tests/riscv64_zvkb.s
+12 −0 src/tests/riscv64_zvkned.s
+157 −68 src/tests/tests.cpp
+6 −5 src/tests/utility.hpp
+2 −0 src/virtual_machine.cpp
+11 −0 src/virtual_machine.hpp
+4 −1 src/virtual_memory.c
+3 −2 src/vm_compiled.cpp
+4 −1 src/vm_compiled.hpp
+1 −0 src/vm_compiled_light.hpp
+33 −8 src/vm_interpreted.cpp
+2 −1 src/vm_interpreted.hpp
+1 −0 src/vm_interpreted_light.hpp
6 changes: 5 additions & 1 deletion src/crypto/hash-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,17 @@ bool tree_branch_hash(const char hash[HASH_SIZE], const char (*branch)[HASH_SIZE
bool is_branch_in_tree(const char hash[HASH_SIZE], const char root[HASH_SIZE], const char (*branch)[HASH_SIZE], size_t depth, uint32_t path);

#define RX_BLOCK_VERSION 12
#define RX_VARIANT_1 1
#define RX_VARIANT_2 2
#define RX_VARIANT_LATEST 0
void rx_slow_hash_allocate_state(void);
void rx_slow_hash_free_state(void);
uint64_t rx_seedheight(const uint64_t height);
void rx_seedheights(const uint64_t height, uint64_t *seed_height, uint64_t *next_height);

void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads);
void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash);
void rx_slow_hash(const char *seedhash, const int variant, const void *data, size_t length, char *result_hash);
void rx_commitment(const void *data, size_t length, const void *rx_hash, char *result_commitment);

void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads);
uint32_t rx_get_miner_thread(void);
94 changes: 68 additions & 26 deletions src/crypto/rx-slow-hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,11 @@ static int secondary_seedhash_set = 0;
#define THREADV __thread
#endif

static THREADV int main_vm_full_variant = 0;
static THREADV randomx_vm *main_vm_full = NULL;
static THREADV int main_vm_light_variant = 0;
static THREADV randomx_vm *main_vm_light = NULL;
static THREADV int secondary_vm_light_variant = 0;
static THREADV randomx_vm *secondary_vm_light = NULL;

static THREADV uint32_t miner_thread = 0;
Expand All @@ -86,7 +89,7 @@ static void local_abort(const char *msg)
#endif
}

static void hash2hex(const char* hash, char* hex) {
static void hash2hex(const char hash[HASH_SIZE], char hex[HASH_SIZE * 2 + 1]) {
const char* d = "0123456789abcdef";
for (int i = 0; i < HASH_SIZE; ++i) {
const uint8_t b = hash[i];
Expand Down Expand Up @@ -133,6 +136,28 @@ static inline int enabled_flags(void) {
return flags;
}

static randomx_flags get_variant_flags(const int variant) {
switch (variant)
{
case RX_VARIANT_1:
break;
case RX_VARIANT_LATEST:
case RX_VARIANT_2:
return RANDOMX_FLAG_V2;
default:
local_abort("Unrecognized RandomX variant");
}

return RANDOMX_FLAG_DEFAULT;
}

static void rx_destroy_vm(randomx_vm** vm) {
if (*vm) {
randomx_destroy_vm(*vm);
*vm = NULL;
}
}

#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */
#define SEEDHASH_EPOCH_LAG 64

Expand Down Expand Up @@ -189,7 +214,7 @@ void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nexth
*nextheight = rx_seedheight(height + get_seedhash_epoch_lag());
}

static void rx_alloc_dataset(randomx_flags flags, randomx_dataset** dataset, int ignore_env)
static void rx_alloc_dataset(randomx_dataset** dataset, int ignore_env)
{
if (*dataset) {
return;
Expand All @@ -213,6 +238,8 @@ static void rx_alloc_dataset(randomx_flags flags, randomx_dataset** dataset, int
return;
}

const randomx_flags flags = enabled_flags();

*dataset = randomx_alloc_dataset((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags());
if (!*dataset) {
alloc_err_msg("Couldn't allocate RandomX dataset using large pages");
Expand All @@ -223,12 +250,14 @@ static void rx_alloc_dataset(randomx_flags flags, randomx_dataset** dataset, int
}
}

static void rx_alloc_cache(randomx_flags flags, randomx_cache** cache)
static void rx_alloc_cache(randomx_cache** cache)
{
if (*cache) {
return;
}

const randomx_flags flags = enabled_flags();

*cache = randomx_alloc_cache((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags());
if (!*cache) {
alloc_err_msg("Couldn't allocate RandomX cache using large pages");
Expand All @@ -237,17 +266,28 @@ static void rx_alloc_cache(randomx_flags flags, randomx_cache** cache)
}
}

static void rx_init_full_vm(randomx_flags flags, randomx_vm** vm)
static void rx_init_full_vm(const int variant, randomx_vm** vm, int* vm_variant)
{
if (*vm || !main_dataset || (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) {
if (!main_dataset || (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) {
return;
}
else if (*vm && variant == *vm_variant) {
return;
}
else if (*vm)
{
// VM is already constructed, but has wrong variant
rx_destroy_vm(vm);
}

randomx_flags flags = enabled_flags();
if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) {
flags |= RANDOMX_FLAG_SECURE;
}
flags |= get_variant_flags(variant);

*vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset);
*vm_variant = variant;
if (!*vm) {
static int shown = 0;
if (!shown) {
Expand All @@ -261,20 +301,28 @@ static void rx_init_full_vm(randomx_flags flags, randomx_vm** vm)
}
}

static void rx_init_light_vm(randomx_flags flags, randomx_vm** vm, randomx_cache* cache)
static void rx_init_light_vm(const int variant, randomx_vm** vm, int* vm_variant, randomx_cache* cache)
{
if (*vm) {
if (*vm && variant == *vm_variant) {
randomx_vm_set_cache(*vm, cache);
return;
}
else if (*vm)
{
// VM is already constructed, but has wrong variant
rx_destroy_vm(vm);
}

randomx_flags flags = enabled_flags();
if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) {
flags |= RANDOMX_FLAG_SECURE;
}
flags |= get_variant_flags(variant);

flags &= ~RANDOMX_FLAG_FULL_MEM;

*vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags(), cache, NULL);
*vm_variant = variant;
if (!*vm) {
static int shown = 0;
if (!shown) {
Expand Down Expand Up @@ -367,9 +415,8 @@ static CTHR_THREAD_RTYPE rx_set_main_seedhash_thread(void *arg) {
hash2hex(main_seedhash, buf);
minfo(RX_LOGCAT, "RandomX new main seed hash is %s", buf);

const randomx_flags flags = enabled_flags() & ~disabled_flags();
rx_alloc_dataset(flags, &main_dataset, 0);
rx_alloc_cache(flags, &main_cache);
rx_alloc_dataset(&main_dataset, 0);
rx_alloc_cache(&main_cache);

randomx_init_cache(main_cache, info->seedhash, HASH_SIZE);
minfo(RX_LOGCAT, "RandomX main cache initialized");
Expand Down Expand Up @@ -405,8 +452,7 @@ void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads)
CTHR_THREAD_CLOSE(t);
}

void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash) {
const randomx_flags flags = enabled_flags() & ~disabled_flags();
void rx_slow_hash(const char *seedhash, const int variant, const void *data, size_t length, char *result_hash) {
int success = 0;

// Fast path (seedhash == main_seedhash)
Expand All @@ -416,7 +462,7 @@ void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *r
if (main_dataset && CTHR_RWLOCK_TRYLOCK_READ(main_dataset_lock)) {
// Double check that main_seedhash didn't change
if (is_main(seedhash)) {
rx_init_full_vm(flags, &main_vm_full);
rx_init_full_vm(variant, &main_vm_full, &main_vm_full_variant);
if (main_vm_full) {
randomx_calculate_hash(main_vm_full, data, length, result_hash);
success = 1;
Expand All @@ -427,7 +473,7 @@ void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *r
CTHR_RWLOCK_LOCK_READ(main_cache_lock);
// Double check that main_seedhash didn't change
if (is_main(seedhash)) {
rx_init_light_vm(flags, &main_vm_light, main_cache);
rx_init_light_vm(variant, &main_vm_light, &main_vm_light_variant, main_cache);
randomx_calculate_hash(main_vm_light, data, length, result_hash);
success = 1;
}
Expand All @@ -449,7 +495,7 @@ void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *r
hash2hex(seedhash, buf);
minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf);

rx_alloc_cache(flags, &secondary_cache);
rx_alloc_cache(&secondary_cache);
randomx_init_cache(secondary_cache, seedhash, HASH_SIZE);
minfo(RX_LOGCAT, "RandomX secondary cache updated");
memcpy(secondary_seedhash, seedhash, HASH_SIZE);
Expand All @@ -460,7 +506,7 @@ void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *r

CTHR_RWLOCK_LOCK_READ(secondary_cache_lock);
if (is_secondary(seedhash)) {
rx_init_light_vm(flags, &secondary_vm_light, secondary_cache);
rx_init_light_vm(variant, &secondary_vm_light, &secondary_vm_light_variant, secondary_cache);
randomx_calculate_hash(secondary_vm_light, data, length, result_hash);
success = 1;
}
Expand All @@ -482,11 +528,15 @@ void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *r
memcpy(secondary_seedhash, seedhash, HASH_SIZE);
secondary_seedhash_set = 1;
}
rx_init_light_vm(flags, &secondary_vm_light, secondary_cache);
rx_init_light_vm(variant, &secondary_vm_light, &secondary_vm_light_variant, secondary_cache);
randomx_calculate_hash(secondary_vm_light, data, length, result_hash);
CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock);
}

void rx_commitment(const void *data, size_t length, const void *rx_hash, char *result_commitment) {
randomx_calculate_commitment(data, length, rx_hash, result_commitment);
}

void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads) {
miner_thread = value;

Expand All @@ -497,8 +547,7 @@ void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads) {
return;
}

const randomx_flags flags = enabled_flags() & ~disabled_flags();
rx_alloc_dataset(flags, &main_dataset, 1);
rx_alloc_dataset(&main_dataset, 1);
rx_init_dataset(max_dataset_init_threads);

CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
Expand All @@ -510,13 +559,6 @@ uint32_t rx_get_miner_thread() {

void rx_slow_hash_allocate_state() {}

static void rx_destroy_vm(randomx_vm** vm) {
if (*vm) {
randomx_destroy_vm(*vm);
*vm = NULL;
}
}

void rx_slow_hash_free_state() {
rx_destroy_vm(&main_vm_full);
rx_destroy_vm(&main_vm_light);
Expand Down
18 changes: 15 additions & 3 deletions src/cryptonote_basic/cryptonote_format_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1438,7 +1438,8 @@ namespace cryptonote
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
crypto::hash tree_root_hash = get_tx_tree_hash(b);
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
if (b.major_version < HF_VERSION_POW_COMMITMENT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you stop including the number of transactions into the hashing blob? This field is used by XMRig, for display purposes.

More importantly, it's a piece of data that gets erased by including only the tree root hash.

Less data that goes into hashing is worse than more data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it because it isn't necessary for consensus and bloats the hashing blob size. If we chose to implement header-only syncing, the varint per hashing blob would impose a non-trivial cost. It shouldn't affect security AFAIK because Keccak isn't susceptible to length extension attacks, but please correct me if wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hashing blob is 75 bytes (76-77 with the tx count). It's not a big difference, and apart for using it to display tx count in XMRig, it's also useful for comparing different hashing blobs between different Monero pools. Things like "which pools use the same Monero node, how many different Monero nodes does a pool use, is it mining empty blocks or not, and so on".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and one more important thing - I'm pretty sure the "76 bytes minimum" is hard-coded in countless pool implementations in many different places, so it's better to not touch it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and apart for using it to display tx count in XMRig, it's also useful for comparing different hashing blobs between different Monero pools. Things like "which pools use the same Monero node, how many different Monero nodes does a pool use, is it mining empty blocks or not, and so on".

I don't think that the number of txs is a very good metric because it can be easily faked. The miner can determine that there's 25 txs in the tx hash list, but that doesn't mean that there's 25 real txs in the hash list; they could all be generated by the pool itself, and of course the fee goes back to the miner.

Oh, and one more important thing - I'm pretty sure the "76 bytes minimum" is hard-coded in countless pool implementations in many different places, so it's better to not touch it.

Why can't they change it to a 75 byte minimum?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/SChernykh/p2pool/blob/master/src/block_template.cpp#L1303
https://github.com/SChernykh/p2pool/blob/master/src/stratum_server.cpp#L140
https://github.com/xmrig/xmrig/blob/master/src/base/tools/cryptonote/BlockTemplate.h#L117
https://github.com/PowPool/xmrpool/blob/main/cnutil/cnutil.go#L11

These were easy to find and will be easy to fix, but how many constants like these are out there and will have to be fixed one by one after they fail?

As for fake/real txs, this varint is not about fake/real. It's about how many txs are in the block template which is an indicator of what the pool is doing. If it says 25, there are 25 transactions of some kind in the block.

blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
return blob;
}
//---------------------------------------------------------------
Expand Down Expand Up @@ -1604,10 +1605,16 @@ namespace cryptonote
return get_tx_tree_hash(txs_ids);
}
//---------------------------------------------------------------
int get_randomx_variant_for_hf_version(const std::uint8_t hf_version)
{
return (hf_version >= HF_VERSION_RANDOMX_V2) ? RX_VARIANT_2 : RX_VARIANT_1;
}
//---------------------------------------------------------------
crypto::hash get_block_longhash(const blobdata_ref block_hashing_blob,
const uint64_t height,
const uint8_t major_version,
const crypto::hash &seed_hash)
const crypto::hash &seed_hash,
crypto::hash &intermediate_hash_out)
{
crypto::hash res;

Expand All @@ -1618,7 +1625,12 @@ namespace cryptonote
}
else if (major_version >= RX_BLOCK_VERSION) // RandomX
{
crypto::rx_slow_hash(seed_hash.data, block_hashing_blob.data(), block_hashing_blob.size(), res.data);
const int rx_variant = get_randomx_variant_for_hf_version(major_version);
crypto::rx_slow_hash(seed_hash.data, rx_variant,
block_hashing_blob.data(), block_hashing_blob.size(), res.data);
intermediate_hash_out = res;
if (major_version >= HF_VERSION_POW_COMMITMENT)
crypto::rx_commitment(block_hashing_blob.data(), block_hashing_blob.size(), res.data, res.data);
}
else // CryptoNight
{
Expand Down
4 changes: 3 additions & 1 deletion src/cryptonote_basic/cryptonote_format_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,12 @@ namespace cryptonote
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
crypto::hash get_tx_tree_hash(const block& b);
int get_randomx_variant_for_hf_version(const std::uint8_t hf_version);
crypto::hash get_block_longhash(const blobdata_ref block_hashing_blob,
const uint64_t height,
const uint8_t major_version,
const crypto::hash &seed_hash);
const crypto::hash &seed_hash,
crypto::hash &intermediate_hash_out);
bool is_valid_decomposed_amount(uint64_t amount);
void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached);

Expand Down
2 changes: 2 additions & 0 deletions src/cryptonote_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@
#define HF_VERSION_BULLETPROOF_PLUS 15
#define HF_VERSION_VIEW_TAGS 15
#define HF_VERSION_2021_SCALING 15
#define HF_VERSION_POW_COMMITMENT 17
#define HF_VERSION_RANDOMX_V2 17

#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
#define CRYPTONOTE_SCALING_2021_FEE_ROUNDING_PLACES 2
Expand Down
2 changes: 1 addition & 1 deletion src/cryptonote_core/cryptonote_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ namespace cryptonote
m_mempool(m_bap.tx_pool),
m_blockchain_storage(m_bap.blockchain),
m_miner(this, [this](const cryptonote::block &b, uint64_t height, const crypto::hash *seed_hash, unsigned int threads, crypto::hash &hash) {
return cryptonote::get_block_longhash(&m_blockchain_storage, b, hash, height, seed_hash, threads);
return cryptonote::get_block_longhash(&m_blockchain_storage, b, hash, height, seed_hash);
}),
m_starter_message_showed(false),
m_target_blockchain_height(0),
Expand Down
Loading
Loading