From 31490c319d1da5d8cc96ac569fccbdab8e8bb07b Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Sun, 13 Nov 2022 10:16:07 +0800 Subject: [PATCH 1/4] per_kb_fee_estimated added --- src/page.h | 39 +++++++++++++++++++++++++++++++++++---- src/rpccalls.cpp | 27 +++++++++++++++++++++++++++ src/rpccalls.h | 3 +++ src/tools.cpp | 2 -- 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/page.h b/src/page.h index e07638a..53b36cc 100644 --- a/src/page.h +++ b/src/page.h @@ -5695,17 +5695,29 @@ json_networkinfo() return j_response; } - uint64_t fee_estimated {0}; + uint64_t per_kb_fee_estimated {0}; // get dynamic fee estimate from last 10 blocks - if (!get_dynamic_per_kb_fee_estimate(fee_estimated)) + if (!get_dynamic_per_kb_fee_estimate(per_kb_fee_estimated)) { j_response["status"] = "error"; - j_response["message"] = "Cant get dynamic fee esimate"; + j_response["message"] = "Cant get per kb dynamic fee esimate"; return j_response; } - j_info["fee_per_kb"] = fee_estimated; + uint64_t fee_estimated {0}; + + // get dynamic fee estimate from last 10 blocks + //@todo: make this work +// if (!get_base_fee_estimate(fee_estimated)) +// { +// j_response["status"] = "error"; +// j_response["message"] = "Cant get dynamic fee esimate"; +// return j_response; +// } + + j_info["fee_per_kb"] = per_kb_fee_estimated; + j_info["fee_estimate"] = fee_estimated; j_info["tx_pool_size"] = MempoolStatus::mempool_no.load(); j_info["tx_pool_size_kbytes"] = MempoolStatus::mempool_size.load(); @@ -6836,6 +6848,25 @@ get_dynamic_per_kb_fee_estimate(uint64_t& fee_estimated) return true; } +bool +get_base_fee_estimate(uint64_t& fee_estimated) +{ + + string error_msg; + + if (!rpc.get_base_fee_estimate( + FEE_ESTIMATE_GRACE_BLOCKS, + fee_estimated)) + { + cerr << "rpc.get_base_fee_estimate failed" << endl; + return false; + } + + (void) error_msg; + + return true; +} + bool are_absolute_offsets_good( std::vector const& absolute_offsets, diff --git a/src/rpccalls.cpp b/src/rpccalls.cpp index 71c689f..eecf9c9 100644 --- a/src/rpccalls.cpp +++ b/src/rpccalls.cpp @@ -40,6 +40,33 @@ rpccalls::connect_to_monero_daemon() return m_http_client.connect(timeout_time_ms); } + +bool +rpccalls::get_base_fee_estimate(uint64_t grace_blocks, + uint64_t& fee_estimate) { + + cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req; + cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response res; + + req.grace_blocks = grace_blocks; + + if (!connect_to_monero_daemon()) + { + cerr << "get_base_fee_estimate: not connected to daemon" << endl; + return false; + } + + bool r = epee::net_utils::invoke_http_json( + "/get_fee_estimate", + req, res, m_http_client, timeout_time_ms); + + fee_estimate = res.fee; + + return r; + + +} + uint64_t rpccalls::get_current_height() { diff --git a/src/rpccalls.h b/src/rpccalls.h index 05dce44..093c0da 100644 --- a/src/rpccalls.h +++ b/src/rpccalls.h @@ -105,6 +105,9 @@ public: bool get_network_info(COMMAND_RPC_GET_INFO::response& info); + bool + get_base_fee_estimate(uint64_t grace_blocks, uint64_t& fee_estimate); + bool get_hardfork_info( COMMAND_RPC_HARD_FORK_INFO::response& res); diff --git a/src/tools.cpp b/src/tools.cpp index 0340552..5341445 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -627,8 +627,6 @@ sum_fees_in_txs(const vector& txs) return fees_sum; } - - vector get_ouputs(const transaction& tx) { From f841622349800316b271ec235d046a1989adb67e Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Wed, 25 Jan 2023 06:37:04 +0800 Subject: [PATCH 2/4] temp fix: https://github.com/moneroexamples/onion-monero-blockchain-explorer/issues/279 Temprorry disabled randomx code generation till figure out what exactly is happening --- main.cpp | 3 + src/crypto/rx-slow-hash.c | 619 ++++++++++++++++++++++++-------------- src/page.h | 30 +- 3 files changed, 409 insertions(+), 243 deletions(-) diff --git a/main.cpp b/main.cpp index a64766e..900f4f7 100644 --- a/main.cpp +++ b/main.cpp @@ -105,6 +105,9 @@ main(int ac, const char* av[]) bool enable_as_hex {*enable_as_hex_opt}; bool enable_emission_monitor {*enable_emission_monitor_opt}; + //temprorary disable randomx + enable_randomx = false; + // set monero log output level uint32_t log_level = 0; mlog_configure("", true); diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c index a0c1787..3c0ef5b 100644 --- a/src/crypto/rx-slow-hash.c +++ b/src/crypto/rx-slow-hash.c @@ -1,4 +1,4 @@ -// Copyright (c) 2019, The Monero Project +// Copyright (c) 2019-2022, The Monero Project // // All rights reserved. // @@ -34,6 +34,7 @@ #include #include #include +#include #include "randomx.h" #include "c_threads.h" @@ -42,31 +43,38 @@ #define RX_LOGCAT "randomx" +static CTHR_RWLOCK_TYPE main_dataset_lock = CTHR_RWLOCK_INIT; +static CTHR_RWLOCK_TYPE main_cache_lock = CTHR_RWLOCK_INIT; + +static randomx_dataset *main_dataset = NULL; +static randomx_cache *main_cache = NULL; +static char main_seedhash[HASH_SIZE]; +static int main_seedhash_set = 0; + +static CTHR_RWLOCK_TYPE secondary_cache_lock = CTHR_RWLOCK_INIT; + +static randomx_cache *secondary_cache = NULL; +static char secondary_seedhash[HASH_SIZE]; +static int secondary_seedhash_set = 0; + #if defined(_MSC_VER) #define THREADV __declspec(thread) #else #define THREADV __thread #endif -typedef struct rx_state { - CTHR_MUTEX_TYPE rs_mutex; - char rs_hash[32]; - uint64_t rs_height; - randomx_cache *rs_cache; -} rx_state; +THREADV randomx_vm *main_vm_full = NULL; +static THREADV randomx_vm *main_vm_light = NULL; +static THREADV randomx_vm *secondary_vm_light = NULL; -static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT; -static CTHR_MUTEX_TYPE rx_dataset_mutex = CTHR_MUTEX_INIT; +static THREADV uint32_t miner_thread = 0; -static rx_state rx_s[2] = {{CTHR_MUTEX_INIT,{0},0,0},{CTHR_MUTEX_INIT,{0},0,0}}; - -static randomx_dataset *rx_dataset; -static uint64_t rx_dataset_height; -THREADV randomx_vm *rx_vm = NULL; -static THREADV int rx_toggle; +static bool is_main(const char* seedhash) { return main_seedhash_set && (memcmp(seedhash, main_seedhash, HASH_SIZE) == 0); } +static bool is_secondary(const char* seedhash) { return secondary_seedhash_set && (memcmp(seedhash, secondary_seedhash, HASH_SIZE) == 0); } static void local_abort(const char *msg) { + merror(RX_LOGCAT, "%s", msg); fprintf(stderr, "%s\n", msg); #ifdef NDEBUG _exit(1); @@ -75,108 +83,196 @@ static void local_abort(const char *msg) #endif } -/** - * @brief uses cpuid to determine if the CPU supports the AES instructions - * @return true if the CPU supports AES, false otherwise - */ +static void hash2hex(const char* hash, char* hex) { + const char* d = "0123456789abcdef"; + for (int i = 0; i < HASH_SIZE; ++i) { + const uint8_t b = hash[i]; + hex[i * 2 + 0] = d[b >> 4]; + hex[i * 2 + 1] = d[b & 15]; + } + hex[HASH_SIZE * 2] = '\0'; +} -static inline int force_software_aes(void) -{ - static int use = -1; +static inline int disabled_flags(void) { + static int flags = -1; - if (use != -1) - return use; + if (flags != -1) { + return flags; + } - const char *env = getenv("MONERO_USE_SOFTWARE_AES"); + const char *env = getenv("MONERO_RANDOMX_UMASK"); if (!env) { - use = 0; - } - else if (!strcmp(env, "0") || !strcmp(env, "no")) { - use = 0; + flags = 0; } else { - use = 1; + char* endptr; + long int value = strtol(env, &endptr, 0); + if (endptr != env && value >= 0 && value < INT_MAX) { + flags = value; + } + else { + flags = 0; + } } - return use; + + return flags; } -static void cpuid(int CPUInfo[4], int InfoType) -{ -#if defined(__x86_64__) - __asm __volatile__ - ( - "cpuid": - "=a" (CPUInfo[0]), - "=b" (CPUInfo[1]), - "=c" (CPUInfo[2]), - "=d" (CPUInfo[3]) : - "a" (InfoType), "c" (0) - ); -#endif +static inline int enabled_flags(void) { + static int flags = -1; + + if (flags != -1) { + return flags; + } + + flags = randomx_get_flags(); + + return flags; } -static inline int check_aes_hw(void) + +#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */ +#define SEEDHASH_EPOCH_LAG 64 + +static inline int is_power_of_2(uint64_t n) { return n && (n & (n-1)) == 0; } + +static int get_seedhash_epoch_lag(void) { -#if defined(__x86_64__) - int cpuid_results[4]; - static int supported = -1; + static unsigned int lag = (unsigned int)-1; + if (lag != (unsigned int)-1) + return lag; + const char *e = getenv("SEEDHASH_EPOCH_LAG"); + if (e) + { + lag = atoi(e); + if (lag > SEEDHASH_EPOCH_LAG || !is_power_of_2(lag)) + lag = SEEDHASH_EPOCH_LAG; + } + else + { + lag = SEEDHASH_EPOCH_LAG; + } + return lag; +} - if(supported >= 0) - return supported; +static unsigned int get_seedhash_epoch_blocks(void) +{ + static unsigned int blocks = (unsigned int)-1; + if (blocks != (unsigned int)-1) + return blocks; + const char *e = getenv("SEEDHASH_EPOCH_BLOCKS"); + if (e) + { + blocks = atoi(e); + if (blocks < 2 || blocks > SEEDHASH_EPOCH_BLOCKS || !is_power_of_2(blocks)) + blocks = SEEDHASH_EPOCH_BLOCKS; + } + else + { + blocks = SEEDHASH_EPOCH_BLOCKS; + } + return blocks; +} - cpuid(cpuid_results,1); - return supported = cpuid_results[2] & (1 << 25); -#else - return 0; -#endif +uint64_t me_rx_seedheight(const uint64_t height) { + const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag(); + const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks(); + uint64_t s_height = (height <= seedhash_epoch_blocks+seedhash_epoch_lag) ? 0 : + (height - seedhash_epoch_lag - 1) & ~(seedhash_epoch_blocks-1); + return s_height; } -static volatile int use_rx_jit_flag = -1; +void me_rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) { + *seedheight = me_rx_seedheight(height); + *nextheight = me_rx_seedheight(height + get_seedhash_epoch_lag()); +} -static inline int use_rx_jit(void) +static void rx_alloc_dataset(randomx_flags flags, randomx_dataset** dataset, int ignore_env) { -#if defined(__x86_64__) - - if (use_rx_jit_flag != -1) - return use_rx_jit_flag; + if (*dataset) { + return; + } - const char *env = getenv("MONERO_USE_RX_JIT"); - if (!env) { - use_rx_jit_flag = 1; + if (disabled_flags() & RANDOMX_FLAG_FULL_MEM) { + static int shown = 0; + if (!shown) { + shown = 1; + minfo(RX_LOGCAT, "RandomX dataset is disabled by MONERO_RANDOMX_UMASK environment variable."); + } + return; } - else if (!strcmp(env, "0") || !strcmp(env, "no")) { - use_rx_jit_flag = 0; + + if (!ignore_env && !getenv("MONERO_RANDOMX_FULL_MEM")) { + static int shown = 0; + if (!shown) { + shown = 1; + minfo(RX_LOGCAT, "RandomX dataset is not enabled by default. Use MONERO_RANDOMX_FULL_MEM environment variable to enable it."); + } + return; } - else { - use_rx_jit_flag = 1; + + *dataset = randomx_alloc_dataset((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags()); + if (!*dataset) { + mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset using large pages"); + *dataset = randomx_alloc_dataset(flags & ~disabled_flags()); + if (!*dataset) { + merror(RX_LOGCAT, "Couldn't allocate RandomX dataset"); + } } - return use_rx_jit_flag; -#else - return 0; -#endif } -#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */ -#define SEEDHASH_EPOCH_LAG 64 +static void rx_alloc_cache(randomx_flags flags, randomx_cache** cache) +{ + if (*cache) { + return; + } -void me_rx_reorg(const uint64_t split_height) { - int i; - CTHR_MUTEX_LOCK(rx_mutex); - for (i=0; i<2; i++) { - if (split_height < rx_s[i].rs_height) - rx_s[i].rs_height = 1; /* set to an invalid seed height */ + *cache = randomx_alloc_cache((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags()); + if (!*cache) { + mwarning(RX_LOGCAT, "Couldn't allocate RandomX cache using large pages"); + *cache = randomx_alloc_cache(flags & ~disabled_flags()); + if (!*cache) local_abort("Couldn't allocate RandomX cache"); } - CTHR_MUTEX_UNLOCK(rx_mutex); } -uint64_t me_rx_seedheight(const uint64_t height) { - uint64_t s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 : - (height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1); - return s_height; +static void rx_init_full_vm(randomx_flags flags, randomx_vm** vm) +{ + if (*vm || !main_dataset || (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) { + return; + } + + if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) { + flags |= RANDOMX_FLAG_SECURE; + } + + *vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset); + if (!*vm) { + mwarning(RX_LOGCAT, "Couldn't allocate RandomX full VM using large pages"); + *vm = randomx_create_vm((flags | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset); + if (!*vm) { + merror(RX_LOGCAT, "Couldn't allocate RandomX full VM"); + } + } } -void me_rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) { - *seedheight = me_rx_seedheight(height); - *nextheight = me_rx_seedheight(height + SEEDHASH_EPOCH_LAG); +static void rx_init_light_vm(randomx_flags flags, randomx_vm** vm, randomx_cache* cache) +{ + if (*vm) { + randomx_vm_set_cache(*vm, cache); + return; + } + + if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) { + flags |= RANDOMX_FLAG_SECURE; + } + + flags &= ~RANDOMX_FLAG_FULL_MEM; + + *vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags(), cache, NULL); + if (!*vm) { + mwarning(RX_LOGCAT, "Couldn't allocate RandomX light VM using large pages"); + *vm = randomx_create_vm(flags & ~disabled_flags(), cache, NULL); + if (!*vm) local_abort("Couldn't allocate RandomX light VM"); + } } typedef struct seedinfo { @@ -185,165 +281,232 @@ typedef struct seedinfo { unsigned long si_count; } seedinfo; -static CTHR_THREAD_RTYPE rx_seedthread(void *arg) { +static CTHR_THREAD_RTYPE me_rx_seedthread(void *arg) { seedinfo *si = arg; - randomx_init_dataset(rx_dataset, si->si_cache, si->si_start, si->si_count); + randomx_init_dataset(main_dataset, si->si_cache, si->si_start, si->si_count); CTHR_THREAD_RETURN; } -static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_t seedheight) { - if (miners > 1) { - unsigned long delta = randomx_dataset_item_count() / miners; - unsigned long start = 0; - int i; - seedinfo *si; - CTHR_THREAD_TYPE *st; - si = malloc(miners * sizeof(seedinfo)); - if (si == NULL) - local_abort("Couldn't allocate RandomX mining threadinfo"); - st = malloc(miners * sizeof(CTHR_THREAD_TYPE)); - if (st == NULL) { - free(si); - local_abort("Couldn't allocate RandomX mining threadlist"); - } - for (i=0; i seedheight) - is_alt = 1; - - toggle ^= (is_alt != 0); - if (toggle != rx_toggle) - changed = 1; - rx_toggle = toggle; - - rx_sp = &rx_s[toggle]; - CTHR_MUTEX_LOCK(rx_sp->rs_mutex); - CTHR_MUTEX_UNLOCK(rx_mutex); - - cache = rx_sp->rs_cache; - if (cache == NULL) { - if (use_rx_jit()) - flags |= RANDOMX_FLAG_JIT; - if (cache == NULL) { - cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES); - if (cache == NULL) { - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX cache"); - cache = randomx_alloc_cache(flags); - } - if (cache == NULL) - local_abort("Couldn't allocate RandomX cache"); - } +typedef struct thread_info { + char seedhash[HASH_SIZE]; + size_t max_threads; +} thread_info; + +static CTHR_THREAD_RTYPE me_rx_set_main_seedhash_thread(void *arg) { + thread_info* info = arg; + + CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock); + CTHR_RWLOCK_LOCK_WRITE(main_cache_lock); + + // Double check that seedhash wasn't already updated + if (is_main(info->seedhash)) { + CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock); + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); + free(info); + CTHR_THREAD_RETURN; } - if (rx_sp->rs_height != seedheight || rx_sp->rs_cache == NULL || memcmp(seedhash, rx_sp->rs_hash, sizeof(rx_sp->rs_hash))) { - randomx_init_cache(cache, seedhash, 32); - rx_sp->rs_cache = cache; - rx_sp->rs_height = seedheight; - memcpy(rx_sp->rs_hash, seedhash, sizeof(rx_sp->rs_hash)); - changed = 1; - } - if (rx_vm == NULL) { - randomx_flags flags = RANDOMX_FLAG_DEFAULT; - if (use_rx_jit()) { - flags |= RANDOMX_FLAG_JIT; - if (!miners) - flags |= RANDOMX_FLAG_SECURE; - } - if(!force_software_aes() && check_aes_hw()) - flags |= RANDOMX_FLAG_HARD_AES; - if (miners) { - CTHR_MUTEX_LOCK(rx_dataset_mutex); - if (rx_dataset == NULL) { - rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); - if (rx_dataset == NULL) { - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset"); - rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); + memcpy(main_seedhash, info->seedhash, HASH_SIZE); + main_seedhash_set = 1; + + char buf[HASH_SIZE * 2 + 1]; + 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); + + randomx_init_cache(main_cache, info->seedhash, HASH_SIZE); + minfo(RX_LOGCAT, "RandomX main cache initialized"); + + CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock); + + // From this point, rx_slow_hash can calculate hashes in light mode, but dataset is not initialized yet + me_rx_init_dataset(info->max_threads); + + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); + + free(info); + CTHR_THREAD_RETURN; +} + +void me_rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads) { + // Early out if seedhash didn't change + if (is_main(seedhash)) { + return; + } + + // Update main cache and dataset in the background + thread_info* info = malloc(sizeof(thread_info)); + if (!info) local_abort("Couldn't allocate RandomX mining threadinfo"); + + memcpy(info->seedhash, seedhash, HASH_SIZE); + info->max_threads = max_dataset_init_threads; + + CTHR_THREAD_TYPE t; + if (!CTHR_THREAD_CREATE(t, me_rx_set_main_seedhash_thread, info)) { + local_abort("Couldn't start RandomX seed thread"); + } +} + +void me_rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash) { + const randomx_flags flags = enabled_flags() & ~disabled_flags(); + int success = 0; + + // Fast path (seedhash == main_seedhash) + // Multiple threads can run in parallel in fast or light mode, 1-2 ms or 10-15 ms per hash per thread + if (is_main(seedhash)) { + // If CTHR_RWLOCK_TRYLOCK_READ fails it means dataset is being initialized now, so use the light mode + 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); + if (main_vm_full) { + randomx_calculate_hash(main_vm_full, data, length, result_hash); + success = 1; } - if (rx_dataset != NULL) - rx_initdata(rx_sp->rs_cache, miners, seedheight); } - if (rx_dataset != NULL) - flags |= RANDOMX_FLAG_FULL_MEM; - else { - miners = 0; - mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset for miner"); + CTHR_RWLOCK_UNLOCK_READ(main_dataset_lock); + } else { + 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); + randomx_calculate_hash(main_vm_light, data, length, result_hash); + success = 1; } - CTHR_MUTEX_UNLOCK(rx_dataset_mutex); - } - rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset); - if(rx_vm == NULL) { //large pages failed - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM"); - rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); + CTHR_RWLOCK_UNLOCK_READ(main_cache_lock); } - if(rx_vm == NULL) {//fallback if everything fails - flags = RANDOMX_FLAG_DEFAULT | (miners ? RANDOMX_FLAG_FULL_MEM : 0); - rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); + } + + if (success) { + return; + } + + char buf[HASH_SIZE * 2 + 1]; + + // Slow path (seedhash != main_seedhash, but seedhash == secondary_seedhash) + // Multiple threads can run in parallel in light mode, 10-15 ms per hash per thread + if (!secondary_cache) { + CTHR_RWLOCK_LOCK_WRITE(secondary_cache_lock); + if (!secondary_cache) { + hash2hex(seedhash, buf); + minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf); + + rx_alloc_cache(flags, &secondary_cache); + randomx_init_cache(secondary_cache, seedhash, HASH_SIZE); + minfo(RX_LOGCAT, "RandomX secondary cache updated"); + memcpy(secondary_seedhash, seedhash, HASH_SIZE); + secondary_seedhash_set = 1; } - if (rx_vm == NULL) - local_abort("Couldn't allocate RandomX VM"); - } else if (miners) { - CTHR_MUTEX_LOCK(rx_dataset_mutex); - if (rx_dataset != NULL && rx_dataset_height != seedheight) - rx_initdata(cache, miners, seedheight); - CTHR_MUTEX_UNLOCK(rx_dataset_mutex); - } else if (changed) { - randomx_vm_set_cache(rx_vm, rx_sp->rs_cache); - } - /* mainchain users can run in parallel */ - if (!is_alt) - CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex); - randomx_calculate_hash(rx_vm, data, length, hash); - /* altchain slot users always get fully serialized */ - if (is_alt) - CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex); -} + CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock); + } + + CTHR_RWLOCK_LOCK_READ(secondary_cache_lock); + if (is_secondary(seedhash)) { + rx_init_light_vm(flags, &secondary_vm_light, secondary_cache); + randomx_calculate_hash(secondary_vm_light, data, length, result_hash); + success = 1; + } + CTHR_RWLOCK_UNLOCK_READ(secondary_cache_lock); -void me_rx_slow_hash_allocate_state(void) { + if (success) { + return; + } + + // Slowest path (seedhash != main_seedhash, seedhash != secondary_seedhash) + // Only one thread runs at a time and updates secondary_seedhash if needed, up to 200-500 ms per hash + CTHR_RWLOCK_LOCK_WRITE(secondary_cache_lock); + if (!is_secondary(seedhash)) { + hash2hex(seedhash, buf); + minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf); + + randomx_init_cache(secondary_cache, seedhash, HASH_SIZE); + minfo(RX_LOGCAT, "RandomX secondary cache updated"); + memcpy(secondary_seedhash, seedhash, HASH_SIZE); + secondary_seedhash_set = 1; + } + rx_init_light_vm(flags, &secondary_vm_light, secondary_cache); + randomx_calculate_hash(secondary_vm_light, data, length, result_hash); + CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock); } -void me_rx_slow_hash_free_state(void) { - if (rx_vm != NULL) { - randomx_destroy_vm(rx_vm); - rx_vm = NULL; +void me_rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads) { + miner_thread = value; + + // If dataset is not allocated yet, try to allocate and initialize it + CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock); + if (main_dataset) { + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); + return; } + + const randomx_flags flags = enabled_flags() & ~disabled_flags(); + rx_alloc_dataset(flags, &main_dataset, 1); + me_rx_init_dataset(max_dataset_init_threads); + + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); +} + +uint32_t me_rx_get_miner_thread() { + return miner_thread; } +void me_rx_slow_hash_allocate_state() {} +static void me_rx_destroy_vm(randomx_vm** vm) { + if (*vm) { + randomx_destroy_vm(*vm); + *vm = NULL; + } +} + +void me_rx_slow_hash_free_state() { + me_rx_destroy_vm(&main_vm_full); + me_rx_destroy_vm(&main_vm_light); + me_rx_destroy_vm(&secondary_vm_light); +} diff --git a/src/page.h b/src/page.h index 53b36cc..5c293e9 100644 --- a/src/page.h +++ b/src/page.h @@ -42,7 +42,7 @@ extern "C" void me_rx_slow_hash(const uint64_t mainheight, const uint64_t seedhe char *hash, int miners, int is_alt); //extern "C" void me_rx_reorg(const uint64_t split_height); -extern __thread randomx_vm *rx_vm; +extern __thread randomx_vm *main_vm_full; #include #include @@ -6978,18 +6978,18 @@ get_randomx_code(uint64_t blk_height, std::lock_guard lk {mtx}; - if (!rx_vm) + if (!main_vm_full) { crypto::hash block_hash; - // this will create rx_vm instance if one + // this will create main_vm_full instance if one // does not exist me_get_block_longhash(core_storage, blk, block_hash, blk_height, 0); - if (!rx_vm) + if (!main_vm_full) { - cerr << "rx_vm is still null!"; + cerr << "main_vm_full is still null!"; return {}; } } @@ -7000,32 +7000,32 @@ get_randomx_code(uint64_t blk_height, alignas(16) uint64_t tempHash[8]; blake2b(tempHash, sizeof(tempHash), bd.data(), bd.size(), nullptr, 0); - rx_vm->initScratchpad(&tempHash); - rx_vm->resetRoundingMode(); + main_vm_full->initScratchpad(&tempHash); + main_vm_full->resetRoundingMode(); for (int chain = 0; chain < RANDOMX_PROGRAM_COUNT - 1; ++chain) { - rx_vm->run(&tempHash); + main_vm_full->run(&tempHash); blake2b(tempHash, sizeof(tempHash), - rx_vm->getRegisterFile(), + main_vm_full->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); rx_code.push_back({}); - rx_code.back().prog = rx_vm->getProgram(); - rx_code.back().reg_file = *(rx_vm->getRegisterFile()); + rx_code.back().prog = main_vm_full->getProgram(); + rx_code.back().reg_file = *(main_vm_full->getRegisterFile()); } - rx_vm->run(&tempHash); + main_vm_full->run(&tempHash); rx_code.push_back({}); - rx_code.back().prog = rx_vm->getProgram(); - rx_code.back().reg_file = *(rx_vm->getRegisterFile()); + rx_code.back().prog = main_vm_full->getProgram(); + rx_code.back().reg_file = *(main_vm_full->getRegisterFile()); //crypto::hash res2; - //rx_vm->getFinalResult(res2.data, RANDOMX_HASH_SIZE); + //main_vm_full->getFinalResult(res2.data, RANDOMX_HASH_SIZE); //cout << "pow2: " << pod_to_hex(res2) << endl; return rx_code; From 5a54019b0ebf23b8c07956e9eaa3d9521e180877 Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 30 Jan 2023 06:35:32 +0800 Subject: [PATCH 3/4] add msg about disabled randomx --- main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 900f4f7..3c208e1 100644 --- a/main.cpp +++ b/main.cpp @@ -106,7 +106,10 @@ main(int ac, const char* av[]) bool enable_emission_monitor {*enable_emission_monitor_opt}; //temprorary disable randomx - enable_randomx = false; + if (enable_randomx == true) { + cout << "Support for randomx code is disabled due to issues with it"<< endl; + enable_randomx = false; + } // set monero log output level uint32_t log_level = 0; From 188d5471b15dbe6bef9d607a84c0bc514ab2747b Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Mon, 30 Jan 2023 06:36:31 +0800 Subject: [PATCH 4/4] readme updated --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 844041d..ecde9df 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,6 @@ The key features of the Onion Monero Blockchain Explorer are: - can provide total amount of all miner fees, - decoding encrypted payment id, - decoding outputs and proving txs sent to sub-address. - - listing RandomX code for each block ## Development branch @@ -244,7 +243,6 @@ xmrblocks, Onion Monero Blockchain Explorer: -t [ --testnet ] [=arg(=1)] (=0) use testnet blockchain -s [ --stagenet ] [=arg(=1)] (=0) use stagenet blockchain --enable-pusher [=arg(=1)] (=0) enable signed transaction pusher - --enable-randomx [=arg(=1)] (=0) enable generation of randomx code --enable-mixin-details [=arg(=1)] (=0) enable mixin details for key images, e.g., timescale, mixin of mixins, in tx