fork rx-slow-hash.c

master
moneroexamples 5 years ago
parent 5583adcc9d
commit 7f1b7ae3fe

@ -71,6 +71,7 @@ message(STATUS ${MONERO_SOURCE_DIR}/build)
# include monero headers # include monero headers
include_directories( include_directories(
${MONERO_SOURCE_DIR}/src ${MONERO_SOURCE_DIR}/src
${MONERO_SOURCE_DIR}/src/crypto
${MONERO_SOURCE_DIR}/external ${MONERO_SOURCE_DIR}/external
${MONERO_SOURCE_DIR}/external/randomx/src ${MONERO_SOURCE_DIR}/external/randomx/src
${MONERO_SOURCE_DIR}/build ${MONERO_SOURCE_DIR}/build

@ -14,7 +14,13 @@ set(SOURCE_FILES
CmdLineOptions.cpp CmdLineOptions.cpp
page.h page.h
rpccalls.cpp rpccalls.h rpccalls.cpp rpccalls.h
version.h.in CurrentBlockchainStatus.cpp MempoolStatus.cpp MempoolStatus.h) version.h.in
CurrentBlockchainStatus.cpp
MempoolStatus.cpp
MempoolStatus.h)
add_subdirectory(crypto)
# make static library called libmyxrm # make static library called libmyxrm
# that we are going to link to # that we are going to link to
@ -22,3 +28,6 @@ set(SOURCE_FILES
add_library(myxrm add_library(myxrm
STATIC STATIC
${SOURCE_FILES}) ${SOURCE_FILES})
target_link_libraries(myxrm mycrypto)

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 2.8)
project(mycrypto)
set(SOURCE_FILES
rx-slow-hash.c)
#include_directories(
# /home/mwo2/monero/external/randomx/src)
# make static library called libmyxrm
# that we are going to link to
# in the root CMakeLists.txt file
add_library(mycrypto
STATIC
${SOURCE_FILES})

@ -0,0 +1,349 @@
// Copyright (c) 2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "randomx.h"
#include "c_threads.h"
#include "hash-ops.h"
#include "misc_log_ex.h"
#define RX_LOGCAT "randomx"
#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;
static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT;
static CTHR_MUTEX_TYPE rx_dataset_mutex = CTHR_MUTEX_INIT;
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 void local_abort(const char *msg)
{
fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG
_exit(1);
#else
abort();
#endif
}
/**
* @brief uses cpuid to determine if the CPU supports the AES instructions
* @return true if the CPU supports AES, false otherwise
*/
static inline int force_software_aes(void)
{
static int use = -1;
if (use != -1)
return use;
const char *env = getenv("MONERO_USE_SOFTWARE_AES");
if (!env) {
use = 0;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use = 0;
}
else {
use = 1;
}
return use;
}
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 check_aes_hw(void)
{
#if defined(__x86_64__)
int cpuid_results[4];
static int supported = -1;
if(supported >= 0)
return supported;
cpuid(cpuid_results,1);
return supported = cpuid_results[2] & (1 << 25);
#else
return 0;
#endif
}
static volatile int use_rx_jit_flag = -1;
static inline int use_rx_jit(void)
{
#if defined(__x86_64__)
if (use_rx_jit_flag != -1)
return use_rx_jit_flag;
const char *env = getenv("MONERO_USE_RX_JIT");
if (!env) {
use_rx_jit_flag = 1;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use_rx_jit_flag = 0;
}
else {
use_rx_jit_flag = 1;
}
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
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 */
}
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;
}
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);
}
typedef struct seedinfo {
randomx_cache *si_cache;
unsigned long si_start;
unsigned long si_count;
} seedinfo;
static CTHR_THREAD_RTYPE rx_seedthread(void *arg) {
seedinfo *si = arg;
randomx_init_dataset(rx_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<miners-1; i++) {
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = delta;
start += delta;
}
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = randomx_dataset_item_count() - start;
for (i=1; i<miners; i++) {
CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i]);
}
randomx_init_dataset(rx_dataset, rs_cache, 0, si[0].si_count);
for (i=1; i<miners; i++) {
CTHR_THREAD_JOIN(st[i]);
}
free(st);
free(si);
} else {
randomx_init_dataset(rx_dataset, rs_cache, 0, randomx_dataset_item_count());
}
rx_dataset_height = seedheight;
}
void me_rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length,
char *hash, int miners, int is_alt) {
uint64_t s_height = me_rx_seedheight(mainheight);
int changed = 0;
int toggle = is_alt ? s_height : seedheight;
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
rx_state *rx_sp;
randomx_cache *cache;
toggle = (toggle & SEEDHASH_EPOCH_BLOCKS) != 0;
CTHR_MUTEX_LOCK(rx_mutex);
/* if alt block but with same seed as mainchain, no need for alt cache */
if (is_alt && s_height == seedheight && !memcmp(rx_s[toggle].rs_hash, seedhash, sizeof(rx_s[toggle].rs_hash)))
is_alt = 0;
/* RPC could request an earlier block on mainchain */
if (!is_alt && s_height > 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");
}
}
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);
}
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_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);
}
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 (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);
}
void me_rx_slow_hash_allocate_state(void) {
}
void me_rx_slow_hash_free_state(void) {
if (rx_vm != NULL) {
randomx_destroy_vm(rx_vm);
rx_vm = NULL;
}
}

@ -36,15 +36,16 @@
#include "../ext/vpetrigocaches/fifo_cache_policy.hpp" #include "../ext/vpetrigocaches/fifo_cache_policy.hpp"
#include "../ext/mstch/src/visitor/render_node.hpp" #include "../ext/mstch/src/visitor/render_node.hpp"
extern "C" bool rx_needhash(const uint64_t height, uint64_t *seedheight); extern "C" bool me_rx_needhash(const uint64_t height, uint64_t *seedheight);
extern "C" void rx_seedhash(const uint64_t seedheight, const char *hash, const int miners); extern "C" void me_rx_seedhash(const uint64_t seedheight, const char *hash, const int miners);
extern "C" void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, extern "C" uint64_t me_rx_seedheight(const uint64_t height);
extern "C" void me_rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight,
const char *seedhash, const char *seedhash,
const void *data, size_t length, const void *data, size_t length,
char *hash, int miners, int is_alt); char *hash, int miners, int is_alt);
extern "C" void rx_reorg(const uint64_t split_height); extern "C" void me_rx_reorg(const uint64_t split_height);
static __thread randomx_vm *rx_vm = NULL; extern __thread randomx_vm *rx_vm;
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
@ -301,6 +302,45 @@ struct randomx_status
} }
}; };
bool
me_get_block_longhash(const Blockchain *pbc,
const block& b,
crypto::hash& res,
const uint64_t height,
const int miners)
{
// block 202612 bug workaround
if (height == 202612)
{
static const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000";
epee::string_tools::hex_to_pod(longhash_202612, res);
return true;
}
blobdata bd = get_block_hashing_blob(b);
if (b.major_version >= RX_BLOCK_VERSION)
{
uint64_t seed_height, main_height;
crypto::hash hash;
if (pbc != NULL)
{
seed_height = me_rx_seedheight(height);
hash = pbc->get_pending_block_id_by_height(seed_height);
main_height = pbc->get_current_blockchain_height();
} else
{
memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block
seed_height = 0;
main_height = 0;
}
me_rx_slow_hash(main_height, seed_height,
hash.data, bd.data(),
bd.size(), res.data, miners, 0);
}
return true;
}
/** /**
* @brief The tx_details struct * @brief The tx_details struct
@ -7207,9 +7247,12 @@ get_randomx_code(uint64_t blk_height,
if (!rx_vm) if (!rx_vm)
{ {
crypto::hash block_hash;
// this will create rx_vm instance if one // this will create rx_vm instance if one
// does not exist // does not exist
get_block_longhash(core_storage, blk, blk_height, 0); me_get_block_longhash(core_storage, blk, block_hash, blk_height, 0);
if (!rx_vm) if (!rx_vm)
{ {

Loading…
Cancel
Save