diff --git a/.gitmodules b/.gitmodules index 8f307487a..b41caf48a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "external/protobuf"] path = external/protobuf url = https://github.com/protocolbuffers/protobuf.git +[submodule "external/randomx"] + path = external/randomx + url = https://github.com/safex/RandomSFX \ No newline at end of file diff --git a/Makefile b/Makefile index 1c014bfcf..6b2f782ae 100644 --- a/Makefile +++ b/Makefile @@ -85,7 +85,7 @@ dist-static: dist-static-proto: mkdir -p build/dist - cd build/dist-protobuf && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_WALLET_RPC=ON -D BUILD_ADVANCED_WALLET=ON ../.. && $(MAKE) + cd build/dist && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_WALLET_RPC=ON -D BUILD_ADVANCED_WALLET=ON ../.. && $(MAKE) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 12271a5ea..8e4d62cb0 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -80,3 +80,4 @@ endif() add_subdirectory(db_drivers) add_subdirectory(easylogging++) +add_subdirectory(randomx EXCLUDE_FROM_ALL) diff --git a/external/randomx b/external/randomx new file mode 160000 index 000000000..4f7b3a9a8 --- /dev/null +++ b/external/randomx @@ -0,0 +1 @@ +Subproject commit 4f7b3a9a8365614ea41c0d865f92a9e855252b66 diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 5fc014b6b..c60633a6d 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -47,8 +47,11 @@ set(crypto_sources random.c skein.c slow-hash.c + rx-slow-hash.c tree-hash.c) +include_directories(${RANDOMX_INCLUDE}) + set(crypto_headers) set(crypto_private_headers @@ -79,6 +82,7 @@ safex_add_library(cncrypto target_link_libraries(cncrypto PUBLIC epee + randomx ${Boost_SYSTEM_LIBRARY} PRIVATE ${EXTRA_LIBRARIES}) diff --git a/src/crypto/c_threads.h b/src/crypto/c_threads.h new file mode 100644 index 000000000..93eae7170 --- /dev/null +++ b/src/crypto/c_threads.h @@ -0,0 +1,60 @@ +// Copyright (c) 2019, The Safex 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. +// +// Parts of this file are originally copyright (c) 2014-2019 The Monero Project + +/* Brain-dead simple portability wrapper over thread APIs for C */ +#pragma once + +#ifdef _WIN32 +#include +#define CTHR_MUTEX_TYPE HANDLE +#define CTHR_MUTEX_INIT NULL +#define CTHR_MUTEX_LOCK(x) do { if (x == NULL) { \ + HANDLE p = CreateMutex(NULL, FALSE, NULL); \ + if (InterlockedCompareExchangePointer((PVOID*)&x, (PVOID)p, NULL) != NULL) \ + CloseHandle(p); \ + } WaitForSingleObject(x, INFINITE); } while(0) +#define CTHR_MUTEX_UNLOCK(x) ReleaseMutex(x) +#define CTHR_THREAD_TYPE HANDLE +#define CTHR_THREAD_RTYPE void +#define CTHR_THREAD_RETURN return +#define CTHR_THREAD_CREATE(thr, func, arg) thr = (HANDLE)_beginthread(func, 0, arg) +#define CTHR_THREAD_JOIN(thr) WaitForSingleObject(thr, INFINITE) +#else +#include +#define CTHR_MUTEX_TYPE pthread_mutex_t +#define CTHR_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER +#define CTHR_MUTEX_LOCK(x) pthread_mutex_lock(&x) +#define CTHR_MUTEX_UNLOCK(x) pthread_mutex_unlock(&x) +#define CTHR_THREAD_TYPE pthread_t +#define CTHR_THREAD_RTYPE void * +#define CTHR_THREAD_RETURN return NULL +#define CTHR_THREAD_CREATE(thr, func, arg) pthread_create(&thr, NULL, func, arg) +#define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL) +#endif diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index 1b401b451..161d3ed9e 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -88,3 +88,11 @@ void hash_extra_jh(const void *data, size_t length, char *hash); void hash_extra_skein(const void *data, size_t length, char *hash); void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash); + +#define RX_BLOCK_VERSION 4 +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_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); +void rx_reorg(const uint64_t split_height); diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c new file mode 100644 index 000000000..6bd4ae28c --- /dev/null +++ b/src/crypto/rx-slow-hash.c @@ -0,0 +1,305 @@ +// Copyright (c) 2019, The Safex 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. +// +// Parts of this file are originally copyright (c) 2014-2019 The Monero Project + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "randomx.h" +#include "c_threads.h" +#include "hash-ops.h" + +#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[HASH_SIZE]; + 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; +static THREADV randomx_vm *rx_vm = NULL; + +static void local_abort(const char *msg) +{ + fprintf(stderr, "%s\n", msg); +#ifdef NDEBUG + _exit(1); +#else + abort(); +#endif +} + +static inline int disabled_flags(void) { + static int flags = -1; + + if (flags != -1) { + return flags; + } + + const char *env = getenv("SAFEX_RANDOMX_UMASK"); + if (!env) { + flags = 0; + } + else { + char* endptr; + long int value = strtol(env, &endptr, 0); + if (endptr != env && value >= 0 && value < INT_MAX) { + flags = value; + } + else { + flags = 0; + } + } + + return flags; +} + +static inline int enabled_flags(void) { + static int flags = -1; + + if (flags != -1) { + return flags; + } + + flags = randomx_get_flags(); + + return flags; +} + +#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */ +#define SEEDHASH_EPOCH_LAG 64 + +void 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) { + if (rx_s[i].rs_height == rx_dataset_height) + rx_dataset_height = 1; + rx_s[i].rs_height = 1; /* set to an invalid seed height */ + } + } + CTHR_MUTEX_UNLOCK(rx_mutex); +} + +uint64_t 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 rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) { + *seedheight = rx_seedheight(height); + *nextheight = 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 seedheight) + is_alt = 1; + /* miner can be ahead of mainchain */ + else if (s_height < seedheight) + toggle ^= 1; + } + + toggle ^= (is_alt != 0); + + 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 (cache == NULL) { + cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES); + if (cache == NULL) + 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, HASH_SIZE)) { + randomx_init_cache(cache, seedhash, HASH_SIZE); + rx_sp->rs_cache = cache; + rx_sp->rs_height = seedheight; + memcpy(rx_sp->rs_hash, seedhash, HASH_SIZE); + } + if (rx_vm == NULL) { + if ((flags & RANDOMX_FLAG_JIT) && !miners) { + flags |= RANDOMX_FLAG_SECURE & ~disabled_flags(); + } + if (miners && (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) { + miners = 0; + } + 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) + 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; + } + 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 + 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 { + /* this is a no-op if the cache hasn't 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 rx_slow_hash_allocate_state(void) { +} + +void rx_slow_hash_free_state(void) { + if (rx_vm != NULL) { + randomx_destroy_vm(rx_vm); + rx_vm = NULL; + } +} + +void rx_stop_mining(void) { + CTHR_MUTEX_LOCK(rx_dataset_mutex); + if (rx_dataset != NULL) { + randomx_dataset *rd = rx_dataset; + rx_dataset = NULL; + randomx_release_dataset(rd); + } + CTHR_MUTEX_UNLOCK(rx_dataset_mutex); +} diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index fb4be50e6..ae980d8df 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -612,7 +612,7 @@ BOOL SetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable) * the allocated buffer. */ -void slow_hash_allocate_state(void) +void cn_slow_hash_allocate_state(void) { if(hp_state != NULL) return; @@ -645,7 +645,7 @@ void slow_hash_allocate_state(void) *@brief frees the state allocated by slow_hash_allocate_state */ -void slow_hash_free_state(void) +void cn_slow_hash_free_state(void) { if(hp_state == NULL) return; @@ -719,7 +719,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int // this isn't supposed to happen, but guard against it for now. if(hp_state == NULL) - slow_hash_allocate_state(); + cn_slow_hash_allocate_state(); /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */ if (prehashed) { @@ -832,13 +832,13 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int } #elif !defined NO_AES && (defined(__arm__) || defined(__aarch64__)) -void slow_hash_allocate_state(void) +void cn_slow_hash_allocate_state(void) { // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c return; } -void slow_hash_free_state(void) +void cn_slow_hash_free_state(void) { // As above return; @@ -1393,13 +1393,13 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int #else // Portable implementation as a fallback -void slow_hash_allocate_state(void) +void cn_slow_hash_allocate_state(void) { // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c return; } -void slow_hash_free_state(void) +void cn_slow_hash_free_state(void) { // As above return; @@ -1577,3 +1577,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int } #endif + +void slow_hash_allocate_state(void) +{ + cn_slow_hash_allocate_state(); + rx_slow_hash_allocate_state(); +} + +void slow_hash_free_state(void) +{ + cn_slow_hash_free_state(); + rx_slow_hash_free_state(); +} diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index e9c04d087..9ab126f19 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1013,15 +1013,6 @@ namespace cryptonote return p; } //--------------------------------------------------------------- - bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height) - { - blobdata bd = get_block_hashing_blob(b); - - const int cn_variant = b.major_version < HF_VERSION_DIFFICULTY_V2 ? b.major_version: HF_VERSION_DIFFICULTY_V2; - crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant); - return true; - } - //--------------------------------------------------------------- std::vector relative_output_offsets_to_absolute(const std::vector& off) { std::vector res = off; @@ -1042,13 +1033,6 @@ namespace cryptonote return res; } //--------------------------------------------------------------- - crypto::hash get_block_longhash(const block& b, uint64_t height) - { - crypto::hash p = null_hash; - get_block_longhash(b, p, height); - return p; - } - //--------------------------------------------------------------- bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) { std::stringstream ss; diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index f22123280..000e1f481 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -110,8 +110,6 @@ namespace cryptonote bool calculate_block_hash(const block& b, crypto::hash& res); bool get_block_hash(const block& b, crypto::hash& res); crypto::hash get_block_hash(const block& b); - bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height); - crypto::hash get_block_longhash(const block& b, uint64_t height); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); bool get_inputs_token_amount(const transaction& tx, uint64_t& tokens); diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 588a94ecb..e2eabef09 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -40,8 +40,10 @@ #include "syncobj.h" #include "cryptonote_basic_impl.h" #include "cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" #include "file_io_utils.h" #include "common/command_line.h" +#include "common/util.h" #include "string_coding.h" #include "string_tools.h" #include "storages/portable_storage_template_helper.h" @@ -96,12 +98,13 @@ namespace cryptonote } - miner::miner(i_miner_handler* phandler):m_stop(1), + miner::miner(i_miner_handler* phandler, Blockchain* pbc):m_stop(1), m_template(boost::value_initialized()), m_template_no(0), m_diffic(0), m_thread_index(0), m_phandler(phandler), + m_pbc(pbc), m_height(0), m_pausers_count(0), m_threads_total(0), @@ -346,6 +349,7 @@ namespace cryptonote { boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1); } + extern "C" void rx_stop_mining(void); //----------------------------------------------------------------------------------------------------- bool miner::stop() { @@ -374,15 +378,16 @@ namespace cryptonote MINFO("Mining has been stopped, " << m_threads.size() << " finished" ); m_threads.clear(); + rx_stop_mining(); return true; } //----------------------------------------------------------------------------------------------------- - bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height) + bool miner::find_nonce_for_given_block(const Blockchain *pbc, block& bl, const difficulty_type& diffic, uint64_t height) { for(; bl.nonce != std::numeric_limits::max(); bl.nonce++) { crypto::hash h; - get_block_longhash(bl, h, height); + get_block_longhash(pbc, bl, h, height, tools::get_max_concurrency()); if(check_hash(h, diffic)) { @@ -480,7 +485,7 @@ namespace cryptonote b.nonce = nonce; crypto::hash h; - get_block_longhash(b, h, height); + get_block_longhash(m_pbc, b, h, height, tools::get_max_concurrency()); if(check_hash(h, local_diff)) { diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index 185967c93..ff9fae291 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -57,13 +57,15 @@ namespace cryptonote ~i_miner_handler(){}; }; + class Blockchain; + /************************************************************************/ /* */ /************************************************************************/ class miner { public: - miner(i_miner_handler* phandler); + miner(i_miner_handler* phandler, Blockchain* pbc); ~miner(); bool init(const boost::program_options::variables_map& vm, network_type nettype); static void init_options(boost::program_options::options_description& desc); @@ -79,7 +81,7 @@ namespace cryptonote bool on_idle(); void on_synchronized(); //synchronous analog (for fast calls) - static bool find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height); + static bool find_nonce_for_given_block(const Blockchain *pbc, block& bl, const difficulty_type& diffic, uint64_t height); void pause(); void resume(); void do_print_hashrate(bool do_hr); @@ -135,6 +137,7 @@ namespace cryptonote std::list m_threads; epee::critical_section m_threads_lock; i_miner_handler* m_phandler; + Blockchain* m_pbc; account_public_address m_mine_address; epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval; epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 05aa18c76..f07266a68 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -106,6 +106,7 @@ #define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 100 //by default, blocks count in blocks downloading +#define BLOCKS_SYNCHRONIZING_MAX_COUNT 2048 //must be a power of 2, greater than 128, equal to SEEDHASH_EPOCH_BLOCKS #define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400*3) //seconds, three days #define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week @@ -193,6 +194,9 @@ namespace config } }; std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b10100028ff33b5dc7640ad6333405a875f9a92cd69e99fc15d208ea2eb990203d1348dc8301011d22a19d7aa99b11c1143fd40e200760de6caa90eab16bd12d0188d6db8537611103c23aed713351b8b88e15bb213983aa03f26aca95da4e77384654153d50a55fc78dcc65a751789b60e816e3710d448b05f56777e66aff4c6228472e6a41e122dc9ab470e5997573adea910e70c4c3a04e3957e33c099848f0fd2d12dc6b84eca3"; uint32_t const GENESIS_NONCE = 10000; + //TODO: Set to other values when activating new hard fork + uint64_t const HARDFORK_V4_INIT_DIFF = 330000000; + uint64_t const HARDFORK_V4_START_HEIGHT = 330000; namespace testnet { @@ -208,6 +212,8 @@ namespace config } }; std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b1010002d4372ec2272690ccd59880807d1fa00f7bd2fa67f7abb350cafbdc24a4ba372c8301011a1ca7d7e74037e4d000a0fc2cc61389ac7d8b0a6b600c62e77374477c4c414d1103a83b4a507df5b0dc5af701078828a1372d77761339a28a7ebb1ff450622f7456d1083f35430eba3353a9e42514480a0cbccbda5ee6abb2d856f8a9aae056a92a6ece1020496a36a4b68341e3b401653139683f8dc27d76ff9eb9c26c2528c26a"; uint32_t const GENESIS_NONCE = 10003; + uint64_t const HARDFORK_V4_INIT_DIFF = 6000; + uint64_t const HARDFORK_V4_START_HEIGHT = 308450; } namespace stagenet @@ -224,6 +230,9 @@ namespace config } }; std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b1010002cd3249adde7fce93280c3a87db72648b7e47eeb08a5e6ff8e926f86e4aa9ffa283010126cb71e5ddd6461fea5d5b00644c5fb9711a2951e1345ba95c648b00ca08e23d1103ab3e85348739c5348f5dd7a61de6e1d30c0a81389ba9ce533da1e65df03f6a71f2df17d26217fb61bd2e8bc65197bf535904d9f5d75e531712f7fd3e255c5ad5308d1ee2cc4166b8effafd2f75d9c8483bb264ed7539cbc2921c580b40b1218b"; uint32_t const GENESIS_NONCE = 10002; + //TODO: Set to other values when activating new hard fork + uint64_t const HARDFORK_V4_INIT_DIFF = 100; + uint64_t const HARDFORK_V4_START_HEIGHT = 241847; } } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index a1c7116cd..534f4761e 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -50,6 +50,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" +#include "crypto/hash-ops.h" #include "cryptonote_core.h" #include "ringct/rctSigs.h" #include "common/perf_timer.h" @@ -100,7 +101,8 @@ static const struct { //version 2 starts from block 61660, around 2018-11-26. Fork time finalized on 2018-11-06 { 2, 61660, 0, 1541503503 }, //version 3 starts from block 92200, fork time finalized on 2019-01-04 - { 3, 92200, 0, 1546602383 } + { 3, 92200, 0, 1546602383 }, + { 4, config::HARDFORK_V4_START_HEIGHT, 0, 1565962165} }; static const uint64_t mainnet_hard_fork_version_1_till = 61659; @@ -113,7 +115,8 @@ static const struct { // version 1 from the start of the blockchain { 1, 1, 0, 1514764801 }, { 2, 33407, 0, 1541066055}, - { 3, 78500, 0, 1546512073} + { 3, 78500, 0, 1546512073}, //184650 + { 4, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1565962165} }; static const uint64_t testnet_hard_fork_version_1_till = 33406; @@ -126,13 +129,15 @@ static const struct { // version 1 from the start of the blockchain { 1, 1, 0, 1560283500 }, { 2, 100, 0, 1561283500}, - { 3, 200, 0, 1562283500} + { 3, 200, 0, 1562283500}, + { 4, config::stagenet::HARDFORK_V4_START_HEIGHT, 0, 1565962165} }; //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0), - m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false) + m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), + m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false), m_prepare_height(0) { LOG_PRINT_L3("Blockchain::" << __func__); } @@ -741,6 +746,21 @@ crypto::hash Blockchain::get_block_id_by_height(uint64_t height) const return null_hash; } //------------------------------------------------------------------ +crypto::hash Blockchain::get_pending_block_id_by_height(uint64_t height) const +{ + if (m_prepare_height && height >= m_prepare_height && height - m_prepare_height < m_prepare_nblocks) + { + std::size_t block_index = height - m_prepare_height; + for (auto &blocks_batches : *m_prepare_blocks) + { + if (block_index < blocks_batches.size()) + return blocks_batches[block_index].hash; + block_index -= blocks_batches.size(); + } + } + return get_block_id_by_height(height); +} +//------------------------------------------------------------------ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -843,16 +863,49 @@ difficulty_type Blockchain::get_difficulty_for_next_block() } size_t target = get_difficulty_target(); - if (m_hardfork->get_current_version() < HF_VERSION_DIFFICULTY_V2) - { - return next_difficulty(timestamps, difficulties, target); - } - else - { - return next_difficulty_v2(timestamps, difficulties, target); - } + return get_hard_fork_difficulty(timestamps, difficulties, target); } + +difficulty_type Blockchain::get_hard_fork_difficulty( std::vector& timestamps, + std::vector& difficulties, size_t& target){ + + uint8_t curr_hardfork_version = m_hardfork->get_current_version(); + auto height = m_db->height(); + + if (curr_hardfork_version < HF_VERSION_DIFFICULTY_V2) + { + return next_difficulty(timestamps, difficulties, target); + } + else + { + uint64_t start_height = 0; + uint64_t random_x_diff = 0; + switch (m_nettype) + { + case STAGENET: + start_height = stagenet_hard_forks[3].height; + random_x_diff = config::stagenet::HARDFORK_V4_INIT_DIFF; + break; + case TESTNET: + start_height = testnet_hard_forks[3].height; + random_x_diff = config::testnet::HARDFORK_V4_INIT_DIFF; + break; + case MAINNET: + start_height = mainnet_hard_forks[3].height; + random_x_diff = config::HARDFORK_V4_INIT_DIFF; + break; + default: + break; + } + + if(height >= start_height && height <= start_height + DIFFICULTY_BLOCKS_COUNT_V2 ) + return random_x_diff; + else + return next_difficulty_v2(timestamps, difficulties, target); + } +} + //------------------------------------------------------------------ // This function removes blocks from the blockchain until it gets to the // position where the blockchain switch started and then re-adds the blocks @@ -987,6 +1040,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::listreorganize_from_chain_height(split_height); + get_block_longhash_reorg(split_height); MGINFO_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height()); return true; @@ -1489,7 +1543,33 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei); CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); crypto::hash proof_of_work = null_hash; - get_block_longhash(bei.bl, proof_of_work, bei.height); + if (b.major_version >= RX_BLOCK_VERSION) + { + crypto::hash seedhash = null_hash; + uint64_t seedheight = rx_seedheight(bei.height); + // seedblock is on the alt chain somewhere + if (alt_chain.size() && alt_chain.front()->second.height <= seedheight) + { + for (auto it = alt_chain.begin(); it != alt_chain.end(); it++) + { + if ((*it)->second.height == seedheight + 1) + { + seedhash = (*it)->second.bl.prev_id; + break; + } + } + } + else + { + seedhash = get_block_id_by_height(seedheight); + } + get_altblock_longhash(bei.bl, proof_of_work, get_current_blockchain_height(), bei.height, seedheight, seedhash); + } + else + { + get_block_longhash(this, bei.bl, proof_of_work, bei.height, 0); + } + if(!check_hash(proof_of_work, current_diff)) { MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff); @@ -3592,7 +3672,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& proof_of_work = it->second; } else - proof_of_work = get_block_longhash(bl, m_db->height()); + proof_of_work = get_block_longhash(this, bl, m_db->height(), 0); // validate proof_of_work versus difficulty target if(!check_hash(proof_of_work, current_diffic)) @@ -3974,7 +4054,7 @@ void Blockchain::block_longhash_worker(uint64_t height, const std::vector if (m_cancel) break; crypto::hash id = get_block_hash(block); - crypto::hash pow = get_block_longhash(block, height++); + crypto::hash pow = get_block_longhash(this, block, height++, 0); map.emplace(id, pow); } @@ -4216,7 +4296,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list 1 && threads > 1 && m_max_prepare_blocks_threads > 1) { @@ -4225,16 +4305,16 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::listheight(); - int batches = blocks_entry.size() / threads; - int extra = blocks_entry.size() % threads; + unsigned int batches = blocks_entry.size() / threads; + unsigned int extra = blocks_entry.size() % threads; MDEBUG("block_batches: " << batches); std::vector> maps(threads); std::vector < std::vector < block >> blocks(threads); auto it = blocks_entry.begin(); - for (uint64_t i = 0; i < threads; i++) + for (unsigned int i = 0; i < threads; i++) { - for (int j = 0; j < batches; j++) + for (unsigned int j = 0; j < batches; j++) { block block; @@ -4263,26 +4343,29 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::listblock, block)) + if (i < extra) { - std::advance(it, 1); - continue; - } + block block; - if (have_block(get_block_hash(block))) - { - blocks_exist = true; - break; - } + if (!parse_and_validate_block_from_blob(it->block, block)) + { + std::advance(it, 1); + continue; + } - blocks[i].push_back(block); - std::advance(it, 1); + if (have_block(get_block_hash(block))) + { + blocks_exist = true; + break; + } + + blocks[i].push_back(block); + std::advance(it, 1); + } } if (!blocks_exist) @@ -4290,6 +4373,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list& timestamps, std::vector& cumulative_difficulties, size_t& target_seconds); + /** * @brief get difficulty target based on chain and hardfork version * @@ -1057,6 +1071,11 @@ namespace cryptonote std::atomic m_cancel; + // for prepare_handle_incoming_blocks + uint64_t m_prepare_height; + uint64_t m_prepare_nblocks; + std::vector> *m_prepare_blocks; + /** * @brief collects the keys for all outputs being "spent" as an input * diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index e4ba1a75e..c89906dfb 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -167,7 +167,7 @@ namespace cryptonote core::core(i_cryptonote_protocol* pprotocol): m_mempool(m_blockchain_storage), m_blockchain_storage(m_mempool), - m_miner(this), + m_miner(this, &m_blockchain_storage), m_miner_address(boost::value_initialized()), m_starter_message_showed(false), m_target_blockchain_height(0), @@ -527,6 +527,8 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); block_sync_size = command_line::get_arg(vm, arg_block_sync_size); + if (block_sync_size > BLOCKS_SYNCHRONIZING_MAX_COUNT) + MERROR("Error --block-sync-size cannot be greater than " << BLOCKS_SYNCHRONIZING_MAX_COUNT); MGINFO("Loading checkpoints"); diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index b4e374bc5..9c3d4e7df 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -38,6 +38,7 @@ using namespace epee; #include "common/apply_permutation.h" #include "cryptonote_tx_utils.h" #include "cryptonote_config.h" +#include "blockchain.h" #include "cryptonote_basic/miner.h" #include "crypto/crypto.h" #include "crypto/hash.h" @@ -737,13 +738,60 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; + bl.invalidate_hashes(); bl.timestamp = 0; bl.nonce = nonce; - miner::find_nonce_for_given_block(bl, 1, 0); - bl.invalidate_hashes(); + miner::find_nonce_for_given_block(NULL, bl, 1, 0); return true; } //--------------------------------------------------------------- + void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, const uint64_t seed_height, const crypto::hash& seed_hash) + { + blobdata bd = get_block_hashing_blob(b); + rx_slow_hash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data, 0, 1); + } + + bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners) + { + 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 = 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; + } + rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, miners, 0); + } + else + { + const int pow_variant = b.major_version < HF_VERSION_DIFFICULTY_V2 ? b.major_version: HF_VERSION_DIFFICULTY_V2; + crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant); + } + return true; + } + + crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners) + { + crypto::hash p = crypto::null_hash; + get_block_longhash(pbc, b, p, height, miners); + return p; + } + + void get_block_longhash_reorg(const uint64_t split_height) + { + rx_reorg(split_height); + } + //--------------------------------------------------------------- cryptonote::tx_source_entry::output_entry generate_migration_bitcoin_transaction_output(const account_keys& sender_account_keys, const crypto::hash bitcoin_tx_hash, uint64_t token_amount) { cryptonote::tx_source_entry::output_entry bitcoin_output{0u, rct::ctkey( diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 3a1e8945c..2155e8ec8 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -128,6 +128,12 @@ namespace cryptonote void set_core_tests_public_key(const crypto::public_key& publicKey); } + class Blockchain; + bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const int miners); + void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, + const uint64_t seed_height, const crypto::hash& seed_hash); + crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const int miners); + void get_block_longhash_reorg(const uint64_t split_height); } BOOST_CLASS_VERSION(cryptonote::tx_source_entry, 0) diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 101b566c6..6ed2fa32f 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -354,6 +354,13 @@ bool t_command_parser_executor::stop_mining(const std::vector& args return m_executor.stop_mining(); } +bool t_command_parser_executor::mining_status(const std::vector& args) +{ + if (!args.empty()) return false; + + return m_executor.mining_status(); +} + bool t_command_parser_executor::stop_daemon(const std::vector& args) { if (!args.empty()) return false; diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index 1d95ab456..1b62c8a30 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -99,6 +99,8 @@ class t_command_parser_executor final bool stop_mining(const std::vector& args); + bool mining_status(const std::vector& args); + bool stop_daemon(const std::vector& args); bool print_status(const std::vector& args); diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 14cf649fc..989c2849f 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -113,6 +113,11 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::stop_mining, &m_parser, p::_1) , "Stop mining." ); + m_command_lookup.set_handler( + "mining_status" + , std::bind(&t_command_parser_executor::mining_status, &m_parser, p::_1) + , "Show current mining status." + ); m_command_lookup.set_handler( "print_pool" , std::bind(&t_command_parser_executor::print_transaction_pool_long, &m_parser, p::_1) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 374cdba00..ac0762182 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -461,6 +461,58 @@ bool t_rpc_command_executor::show_status() { return true; } +bool t_rpc_command_executor::mining_status() +{ + cryptonote::COMMAND_RPC_MINING_STATUS::request mreq; + cryptonote::COMMAND_RPC_MINING_STATUS::response mres; + epee::json_rpc::error error_resp; + bool has_mining_info = true; + + std::string fail_message = "Problem fetching info"; + + bool mining_busy = false; + if (m_is_rpc) + { + // mining info is only available non unrestricted RPC mode + has_mining_info = m_rpc_client->rpc_request(mreq, mres, "/mining_status", fail_message.c_str()); + } + else + { + if (!m_rpc_server->on_mining_status(mreq, mres)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + + if (mres.status == CORE_RPC_STATUS_BUSY) + mining_busy = true; + else if (mres.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << make_error(fail_message, mres.status); + return true; + } + } + + if (!has_mining_info) + { + tools::fail_msg_writer() << "Mining info unavailable"; + return true; + } + + if (mining_busy || !mres.active) + tools::msg_writer() << "Not currently mining"; + else + tools::msg_writer() << "Mining at " << get_mining_speed(mres.speed) << " with " << mres.threads_count << " threads"; + + if (mres.active || mres.is_background_mining_enabled) + { + tools::msg_writer() << "PoW algorithm: " << mres.pow_algorithm; + tools::msg_writer() << "Mining address: " << mres.address; + } + + return true; +} + bool t_rpc_command_executor::print_connections() { cryptonote::COMMAND_RPC_GET_CONNECTIONS::request req = AUTO_VAL_INIT(req); cryptonote::COMMAND_RPC_GET_CONNECTIONS::response res = AUTO_VAL_INIT(res); diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index e768dd761..d48cc8214 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -110,6 +110,8 @@ class t_rpc_command_executor final { bool stop_mining(); + bool mining_status(); + bool stop_daemon(); bool print_status(); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 0993b3ed7..3ae270e0b 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -978,6 +978,16 @@ namespace cryptonote res.threads_count = lMiner.get_threads_count(); const account_public_address& lMiningAdr = lMiner.get_mining_address(); res.address = get_account_address_as_str(m_nettype, false, lMiningAdr); + const uint8_t major_version = m_core.get_blockchain_storage().get_current_hard_fork_version(); + const unsigned variant = (major_version < RX_BLOCK_VERSION ? major_version : RX_BLOCK_VERSION) - 1; + switch (variant) + { + case 0: res.pow_algorithm = "Cryptonight"; break; + case 1: res.pow_algorithm = "CNv1 (Cryptonight variant 1)"; break; + case 2: res.pow_algorithm = "CNv2 (Cryptonight variant 2)"; break; + case 3: res.pow_algorithm = "RandomX"; break; + default: res.pow_algorithm = "I'm not sure actually"; break; + } } res.status = CORE_RPC_STATUS_OK; @@ -1215,6 +1225,18 @@ namespace cryptonote LOG_ERROR("Failed to create block template"); return false; } + if (b.major_version >= RX_BLOCK_VERSION) + { + uint64_t seed_height, next_height; + crypto::hash seed_hash; + crypto::rx_seedheights(res.height, &seed_height, &next_height); + seed_hash = m_core.get_block_id_by_height(seed_height); + res.seed_hash = string_tools::pod_to_hex(seed_hash); + if (next_height != seed_height) { + seed_hash = m_core.get_block_id_by_height(next_height); + res.next_seed_hash = string_tools::pod_to_hex(seed_hash); + } + } blobdata block_blob = t_serializable_object_to_blob(b); crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx); if(tx_pub_key == crypto::null_pkey) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index e9b8eaadb..74ee6d0bf 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -1188,6 +1188,7 @@ namespace cryptonote uint64_t speed; uint32_t threads_count; std::string address; + std::string pow_algorithm; bool is_background_mining_enabled; BEGIN_KV_SERIALIZE_MAP() @@ -1196,6 +1197,7 @@ namespace cryptonote KV_SERIALIZE(speed) KV_SERIALIZE(threads_count) KV_SERIALIZE(address) + KV_SERIALIZE(pow_algorithm) KV_SERIALIZE(is_background_mining_enabled) END_KV_SERIALIZE_MAP() }; @@ -1272,6 +1274,8 @@ namespace cryptonote uint64_t reserved_offset; uint64_t expected_reward; std::string prev_hash; + std::string seed_hash; + std::string next_seed_hash; blobdata blocktemplate_blob; blobdata blockhashing_blob; std::string status; @@ -1287,6 +1291,8 @@ namespace cryptonote KV_SERIALIZE(blockhashing_blob) KV_SERIALIZE(status) KV_SERIALIZE(untrusted) + KV_SERIALIZE(seed_hash) + KV_SERIALIZE(next_seed_hash) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init response; diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp index f12ed1d5e..82d355cd0 100644 --- a/tests/core_proxy/core_proxy.cpp +++ b/tests/core_proxy/core_proxy.cpp @@ -210,7 +210,7 @@ bool tests::proxy_core::handle_incoming_block(const cryptonote::blobdata& block_ crypto::hash lh; cout << "BLOCK" << endl << endl; cout << (h = get_block_hash(b)) << endl; - cout << (lh = get_block_longhash(b, 0)) << endl; + cout << (lh = get_block_longhash(NULL, b, 0, 0)) << endl; cout << get_transaction_hash(b.miner_tx) << endl; cout << ::get_object_blobsize(b.miner_tx) << endl; //cout << string_tools::buff_to_hex_nodelimer(block_blob) << endl; @@ -237,7 +237,7 @@ void tests::proxy_core::get_blockchain_top(uint64_t& height, crypto::hash& top_i bool tests::proxy_core::init(const boost::program_options::variables_map& /*vm*/) { generate_genesis_block(m_genesis, config::GENESIS_TX, config::GENESIS_NONCE); crypto::hash h = get_block_hash(m_genesis); - add_block(h, get_block_longhash(m_genesis, 0), m_genesis, block_to_blob(m_genesis)); + add_block(h, get_block_longhash(NULL, m_genesis, 0, 0), m_genesis, block_to_blob(m_genesis)); return true; } diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 321417f12..8584ca809 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -181,7 +181,7 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co // Nonce search... blk.nonce = 0; - while (!miner::find_nonce_for_given_block(blk, get_test_difficulty(), height)) + while (!miner::find_nonce_for_given_block(NULL, blk, get_test_difficulty(), height)) blk.timestamp++; const uint8_t hf_version = 1; //hardcode hf version for tests @@ -731,7 +731,7 @@ void fill_token_tx_sources_and_destinations(const std::vector& void fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height) { blk.nonce = 0; - while (!miner::find_nonce_for_given_block(blk, diffic, height)) + while (!miner::find_nonce_for_given_block(NULL, blk, diffic, height)) blk.timestamp++; } diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp index 398791332..4683a0da0 100644 --- a/tests/unit_tests/blockchain_db.cpp +++ b/tests/unit_tests/blockchain_db.cpp @@ -93,7 +93,7 @@ static bool find_nonce_for_given_block(block &bl, const difficulty_type &diffic, for (; bl.nonce != std::numeric_limits::max(); bl.nonce++) { crypto::hash h; - get_block_longhash(bl, h, height); + get_block_longhash(NULL, bl, h, height, 0); if (check_hash(h, diffic)) {