Compare commits

...

10 Commits

Author SHA1 Message Date
lza_menace 4513845a19 wowify 11 months ago
moneroexamples d66972065f
Merge pull request #287 from erciccione/patch-1
css: fix overflowing text in cells
1 year ago
ErC b3b84af960
css: fix overflowing text in cells
Long strings without spaces don't get wrapped and will result in the text overflowing outside of the cell and messing up the structure of the page. See for example [the tx_extra field in this transaction](https://xmrchain.net/search?value=1ecce7898a4e1c7334241c834ba4866d6b511ee896c318b3445aea1cc926e40f).

This small patch makes long text wrap inside the given limit, which would be otherwise "ignored".
1 year ago
moneroexamples 6c5d7b17c6
Merge pull request #281 from moneroexamples/devel
Devel
1 year ago
moneroexamples 188d5471b1 readme updated 1 year ago
moneroexamples 5a54019b0e add msg about disabled randomx 1 year ago
moneroexamples f841622349 temp fix: https://github.com/moneroexamples/onion-monero-blockchain-explorer/issues/279
Temprorry disabled randomx code generation till figure out
what exactly is happening
1 year ago
moneroexamples 31490c319d per_kb_fee_estimated added 1 year ago
moneroexamples aa96ce2927
Merge pull request #274 from moneroexamples/devel
For monero release v0.18
2 years ago
moneroexamples dc2d06b141 Update dockerfile 2 years ago

@ -14,7 +14,7 @@ endif()
if (NOT MONERO_DIR) if (NOT MONERO_DIR)
set(MONERO_DIR ~/monero) set(MONERO_DIR ~/wownero)
endif() endif()
message(STATUS MONERO_DIR ": ${MONERO_DIR}") message(STATUS MONERO_DIR ": ${MONERO_DIR}")

@ -3,7 +3,7 @@ FROM ubuntu:20.04 as builder
# Set Monero branch/tag to be used for monerod compilation # Set Monero branch/tag to be used for monerod compilation
ARG MONERO_BRANCH=release-v18 ARG MONERO_BRANCH=release-v0.18
# Added DEBIAN_FRONTEND=noninteractive to workaround tzdata prompt on installation # Added DEBIAN_FRONTEND=noninteractive to workaround tzdata prompt on installation
ENV DEBIAN_FRONTEND="noninteractive" ENV DEBIAN_FRONTEND="noninteractive"

@ -72,7 +72,6 @@ The key features of the Onion Monero Blockchain Explorer are:
- can provide total amount of all miner fees, - can provide total amount of all miner fees,
- decoding encrypted payment id, - decoding encrypted payment id,
- decoding outputs and proving txs sent to sub-address. - decoding outputs and proving txs sent to sub-address.
- listing RandomX code for each block
## Development branch ## Development branch
@ -244,7 +243,6 @@ xmrblocks, Onion Monero Blockchain Explorer:
-t [ --testnet ] [=arg(=1)] (=0) use testnet blockchain -t [ --testnet ] [=arg(=1)] (=0) use testnet blockchain
-s [ --stagenet ] [=arg(=1)] (=0) use stagenet blockchain -s [ --stagenet ] [=arg(=1)] (=0) use stagenet blockchain
--enable-pusher [=arg(=1)] (=0) enable signed transaction pusher --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 [=arg(=1)] (=0)
enable mixin details for key images, enable mixin details for key images,
e.g., timescale, mixin of mixins, in tx e.g., timescale, mixin of mixins, in tx

@ -45,7 +45,7 @@ foreach (l ${LIBS})
find_library(Xmr_${L}_LIBRARY find_library(Xmr_${L}_LIBRARY
NAMES ${l} NAMES ${l}
PATHS ${CMAKE_LIBRARY_PATH} PATHS ${CMAKE_LIBRARY_PATH}
PATH_SUFFIXES "/src/${l}" "/src/" "/external/db_drivers/lib${l}" "/lib" "/src/crypto" "/src/crypto/wallet" "/contrib/epee/src" "/external/easylogging++/" "/external/${l}" "external/miniupnp/miniupnpc" PATH_SUFFIXES "/src/${l}" "/src/" "/external/db_drivers/lib${l}" "/lib" "/src/crypto" "/src/crypto/wallet" "/contrib/epee/src" "/external/easylogging++/" "/external/${l}" "external/miniupnp/miniupnpc" "/external/randomwow"
NO_DEFAULT_PATH NO_DEFAULT_PATH
) )
@ -83,7 +83,7 @@ include_directories(
${MONERO_SOURCE_DIR}/src/crypto ${MONERO_SOURCE_DIR}/src/crypto
${MONERO_SOURCE_DIR}/src/crypto/wallet ${MONERO_SOURCE_DIR}/src/crypto/wallet
${MONERO_SOURCE_DIR}/external ${MONERO_SOURCE_DIR}/external
${MONERO_SOURCE_DIR}/external/randomx/src ${MONERO_SOURCE_DIR}/external/randomwow/src
${MONERO_SOURCE_DIR}/build ${MONERO_SOURCE_DIR}/build
${MONERO_SOURCE_DIR}/external/easylogging++ ${MONERO_SOURCE_DIR}/external/easylogging++
${MONERO_SOURCE_DIR}/contrib/epee/include ${MONERO_SOURCE_DIR}/contrib/epee/include

@ -105,6 +105,12 @@ main(int ac, const char* av[])
bool enable_as_hex {*enable_as_hex_opt}; bool enable_as_hex {*enable_as_hex_opt};
bool enable_emission_monitor {*enable_emission_monitor_opt}; bool enable_emission_monitor {*enable_emission_monitor_opt};
//temprorary disable randomx
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 // set monero log output level
uint32_t log_level = 0; uint32_t log_level = 0;
mlog_configure("", true); mlog_configure("", true);
@ -208,9 +214,9 @@ main(int ac, const char* av[])
string daemon_url {*daemon_url_opt}; string daemon_url {*daemon_url_opt};
if (testnet && daemon_url == "127.0.0.1:18081") if (testnet && daemon_url == "127.0.0.1:34568")
daemon_url = "127.0.0.1:28081"; daemon_url = "127.0.0.1:11181";
if (stagenet && daemon_url == "127.0.0.1:18081") if (stagenet && daemon_url == "127.0.0.1:34568")
daemon_url = "127.0.0.1:38081"; daemon_url = "127.0.0.1:38081";
uint64_t mempool_info_timeout {5000}; uint64_t mempool_info_timeout {5000};
@ -484,7 +490,7 @@ main(int ac, const char* av[])
|| post_body.count("txprvkey") == 0 || post_body.count("txprvkey") == 0
|| post_body.count("txhash") == 0) || post_body.count("txhash") == 0)
{ {
return string("xmr address, tx private key or " return string("wow address, tx private key or "
"tx hash not provided"); "tx hash not provided");
} }

@ -18,7 +18,7 @@ namespace xmreg
p.add("txhash", -1); p.add("txhash", -1);
options_description desc( options_description desc(
"xmrblocks, Onion Monero Blockchain Explorer"); "xmrblocks, Onion Wownero Blockchain Explorer");
desc.add_options() desc.add_options()
("help,h", value<bool>()->default_value(false)->implicit_value(true), ("help,h", value<bool>()->default_value(false)->implicit_value(true),
@ -44,7 +44,7 @@ namespace xmreg
("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true), ("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),
"enable users to have the index page on autorefresh") "enable users to have the index page on autorefresh")
("enable-emission-monitor", value<bool>()->default_value(false)->implicit_value(true), ("enable-emission-monitor", value<bool>()->default_value(false)->implicit_value(true),
"enable Monero total emission monitoring thread") "enable Wownero total emission monitoring thread")
("port,p", value<string>()->default_value("8081"), ("port,p", value<string>()->default_value("8081"),
"default explorer port") "default explorer port")
("bindaddr,x", value<string>()->default_value("0.0.0.0"), ("bindaddr,x", value<string>()->default_value("0.0.0.0"),
@ -64,7 +64,7 @@ namespace xmreg
("concurrency,c", value<size_t>()->default_value(0), ("concurrency,c", value<size_t>()->default_value(0),
"number of threads handling http queries. Default is 0 which means it is based you on the cpu") "number of threads handling http queries. Default is 0 which means it is based you on the cpu")
("bc-path,b", value<string>(), ("bc-path,b", value<string>(),
"path to lmdb folder of the blockchain, e.g., ~/.bitmonero/lmdb") "path to lmdb folder of the blockchain, e.g., ~/.wownero/lmdb")
("ssl-crt-file", value<string>(), ("ssl-crt-file", value<string>(),
"path to crt file for ssl (https) functionality") "path to crt file for ssl (https) functionality")
("ssl-key-file", value<string>(), ("ssl-key-file", value<string>(),
@ -72,7 +72,7 @@ namespace xmreg
("daemon-login", value<string>(), ("daemon-login", value<string>(),
"Specify username[:password] for daemon RPC client") "Specify username[:password] for daemon RPC client")
("daemon-url,d", value<string>()->default_value("127.0.0.1:18081"), ("daemon-url,d", value<string>()->default_value("127.0.0.1:18081"),
"Monero daemon url") "Wownero daemon url")
("enable-mixin-guess", value<bool>()->default_value(false)->implicit_value(true), ("enable-mixin-guess", value<bool>()->default_value(false)->implicit_value(true),
"enable guessing real outputs in key images based on viewkey"); "enable guessing real outputs in key images based on viewkey");

@ -297,13 +297,13 @@ CurrentBlockchainStatus::is_thread_running()
return is_running; return is_running;
} }
bf::path CurrentBlockchainStatus::blockchain_path {"/home/mwo/.bitmonero/lmdb"}; bf::path CurrentBlockchainStatus::blockchain_path {"/home/mwo/.wownero/lmdb"};
cryptonote::network_type CurrentBlockchainStatus::nettype {cryptonote::network_type::MAINNET}; cryptonote::network_type CurrentBlockchainStatus::nettype {cryptonote::network_type::MAINNET};
string CurrentBlockchainStatus::output_file {"emission_amount.txt"}; string CurrentBlockchainStatus::output_file {"emission_amount.txt"};
string CurrentBlockchainStatus::daemon_url {"http:://127.0.0.1:18081"}; string CurrentBlockchainStatus::daemon_url {"http:://127.0.0.1:234568"};
uint64_t CurrentBlockchainStatus::blockchain_chunk_size {10000}; uint64_t CurrentBlockchainStatus::blockchain_chunk_size {10000};

@ -328,8 +328,8 @@ MempoolStatus::is_thread_running()
return is_running; return is_running;
} }
bf::path MempoolStatus::blockchain_path {"/home/mwo/.bitmonero/lmdb"}; bf::path MempoolStatus::blockchain_path {"/home/mwo/.wownero/lmdb"};
string MempoolStatus::daemon_url {"http:://127.0.0.1:18081"}; string MempoolStatus::daemon_url {"http:://127.0.0.1:34568"};
cryptonote::network_type MempoolStatus::nettype {cryptonote::network_type::MAINNET}; cryptonote::network_type MempoolStatus::nettype {cryptonote::network_type::MAINNET};
atomic<bool> MempoolStatus::is_running {false}; atomic<bool> MempoolStatus::is_running {false};
boost::thread MempoolStatus::m_thread; boost::thread MempoolStatus::m_thread;

@ -1,4 +1,4 @@
// Copyright (c) 2019, The Monero Project // Copyright (c) 2019-2022, The Monero Project
// //
// All rights reserved. // All rights reserved.
// //
@ -34,6 +34,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h>
#include "randomx.h" #include "randomx.h"
#include "c_threads.h" #include "c_threads.h"
@ -42,31 +43,38 @@
#define RX_LOGCAT "randomx" #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) #if defined(_MSC_VER)
#define THREADV __declspec(thread) #define THREADV __declspec(thread)
#else #else
#define THREADV __thread #define THREADV __thread
#endif #endif
typedef struct rx_state { THREADV randomx_vm *main_vm_full = NULL;
CTHR_MUTEX_TYPE rs_mutex; static THREADV randomx_vm *main_vm_light = NULL;
char rs_hash[32]; static THREADV randomx_vm *secondary_vm_light = NULL;
uint64_t rs_height;
randomx_cache *rs_cache;
} rx_state;
static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT; static THREADV uint32_t miner_thread = 0;
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 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 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) static void local_abort(const char *msg)
{ {
merror(RX_LOGCAT, "%s", msg);
fprintf(stderr, "%s\n", msg); fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG #ifdef NDEBUG
_exit(1); _exit(1);
@ -75,108 +83,196 @@ static void local_abort(const char *msg)
#endif #endif
} }
/** static void hash2hex(const char* hash, char* hex) {
* @brief uses cpuid to determine if the CPU supports the AES instructions const char* d = "0123456789abcdef";
* @return true if the CPU supports AES, false otherwise 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 inline int disabled_flags(void) {
{ static int flags = -1;
static int use = -1;
if (use != -1) if (flags != -1) {
return use; return flags;
}
const char *env = getenv("MONERO_USE_SOFTWARE_AES"); const char *env = getenv("MONERO_RANDOMX_UMASK");
if (!env) { if (!env) {
use = 0; flags = 0;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use = 0;
} }
else { 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) static inline int enabled_flags(void) {
{ static int flags = -1;
#if defined(__x86_64__)
__asm __volatile__ if (flags != -1) {
( return flags;
"cpuid": }
"=a" (CPUInfo[0]),
"=b" (CPUInfo[1]), flags = randomx_get_flags();
"=c" (CPUInfo[2]),
"=d" (CPUInfo[3]) : return flags;
"a" (InfoType), "c" (0)
);
#endif
} }
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__) static unsigned int lag = (unsigned int)-1;
int cpuid_results[4]; if (lag != (unsigned int)-1)
static int supported = -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) static unsigned int get_seedhash_epoch_blocks(void)
return supported; {
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); uint64_t me_rx_seedheight(const uint64_t height) {
return supported = cpuid_results[2] & (1 << 25); const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag();
#else const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks();
return 0; uint64_t s_height = (height <= seedhash_epoch_blocks+seedhash_epoch_lag) ? 0 :
#endif (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 (*dataset) {
return;
if (use_rx_jit_flag != -1) }
return use_rx_jit_flag;
const char *env = getenv("MONERO_USE_RX_JIT"); if (disabled_flags() & RANDOMX_FLAG_FULL_MEM) {
if (!env) { static int shown = 0;
use_rx_jit_flag = 1; 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 */ static void rx_alloc_cache(randomx_flags flags, randomx_cache** cache)
#define SEEDHASH_EPOCH_LAG 64 {
if (*cache) {
return;
}
void me_rx_reorg(const uint64_t split_height) { *cache = randomx_alloc_cache((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags());
int i; if (!*cache) {
CTHR_MUTEX_LOCK(rx_mutex); mwarning(RX_LOGCAT, "Couldn't allocate RandomX cache using large pages");
for (i=0; i<2; i++) { *cache = randomx_alloc_cache(flags & ~disabled_flags());
if (split_height < rx_s[i].rs_height) if (!*cache) local_abort("Couldn't allocate RandomX cache");
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) { static void rx_init_full_vm(randomx_flags flags, randomx_vm** vm)
uint64_t s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 : {
(height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1); if (*vm || !main_dataset || (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) {
return s_height; 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) { static void rx_init_light_vm(randomx_flags flags, randomx_vm** vm, randomx_cache* cache)
*seedheight = me_rx_seedheight(height); {
*nextheight = me_rx_seedheight(height + SEEDHASH_EPOCH_LAG); 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 { typedef struct seedinfo {
@ -185,165 +281,232 @@ typedef struct seedinfo {
unsigned long si_count; unsigned long si_count;
} seedinfo; } seedinfo;
static CTHR_THREAD_RTYPE rx_seedthread(void *arg) { static CTHR_THREAD_RTYPE me_rx_seedthread(void *arg) {
seedinfo *si = 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; CTHR_THREAD_RETURN;
} }
static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_t seedheight) { static void me_rx_init_dataset(size_t max_threads) {
if (miners > 1) { if (!main_dataset) {
unsigned long delta = randomx_dataset_item_count() / miners; return;
unsigned long start = 0; }
int i;
seedinfo *si; // leave 2 CPU cores for other tasks
CTHR_THREAD_TYPE *st; const size_t num_threads = (max_threads < 4) ? 1 : (max_threads - 2);
si = malloc(miners * sizeof(seedinfo)); seedinfo* si = malloc(num_threads * sizeof(seedinfo));
if (si == NULL) if (!si) local_abort("Couldn't allocate RandomX mining threadinfo");
local_abort("Couldn't allocate RandomX mining threadinfo");
st = malloc(miners * sizeof(CTHR_THREAD_TYPE)); const uint32_t delta = randomx_dataset_item_count() / num_threads;
if (st == NULL) { uint32_t start = 0;
free(si);
local_abort("Couldn't allocate RandomX mining threadlist"); const size_t n1 = num_threads - 1;
} for (size_t i = 0; i < n1; ++i) {
for (i=0; i<miners-1; i++) { si[i].si_cache = main_cache;
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_start = start;
si[i].si_count = randomx_dataset_item_count() - start; si[i].si_count = delta;
for (i=1; i<miners; i++) { start += delta;
CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i]); }
}
randomx_init_dataset(rx_dataset, rs_cache, 0, si[0].si_count); si[n1].si_cache = main_cache;
for (i=1; i<miners; i++) { si[n1].si_start = start;
CTHR_THREAD_JOIN(st[i]); si[n1].si_count = randomx_dataset_item_count() - start;
CTHR_THREAD_TYPE *st = malloc(num_threads * sizeof(CTHR_THREAD_TYPE));
if (!st) local_abort("Couldn't allocate RandomX mining threadlist");
CTHR_RWLOCK_LOCK_READ(main_cache_lock);
for (size_t i = 0; i < n1; ++i) {
if (!CTHR_THREAD_CREATE(st[i], me_rx_seedthread, &si[i])) {
local_abort("Couldn't start RandomX seed thread");
} }
free(st);
free(si);
} else {
randomx_init_dataset(rx_dataset, rs_cache, 0, randomx_dataset_item_count());
} }
rx_dataset_height = seedheight; me_rx_seedthread(&si[n1]);
for (size_t i = 0; i < n1; ++i) CTHR_THREAD_JOIN(st[i]);
CTHR_RWLOCK_UNLOCK_READ(main_cache_lock);
free(st);
free(si);
minfo(RX_LOGCAT, "RandomX dataset initialized");
} }
void me_rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, typedef struct thread_info {
char *hash, int miners, int is_alt) { char seedhash[HASH_SIZE];
uint64_t s_height = me_rx_seedheight(mainheight); size_t max_threads;
int changed = 0; } thread_info;
int toggle = is_alt ? s_height : seedheight;
randomx_flags flags = RANDOMX_FLAG_DEFAULT; static CTHR_THREAD_RTYPE me_rx_set_main_seedhash_thread(void *arg) {
rx_state *rx_sp; thread_info* info = arg;
randomx_cache *cache;
CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock);
toggle = (toggle & SEEDHASH_EPOCH_BLOCKS) != 0; CTHR_RWLOCK_LOCK_WRITE(main_cache_lock);
CTHR_MUTEX_LOCK(rx_mutex);
// Double check that seedhash wasn't already updated
/* if alt block but with same seed as mainchain, no need for alt cache */ if (is_main(info->seedhash)) {
if (is_alt && s_height == seedheight && !memcmp(rx_s[toggle].rs_hash, seedhash, sizeof(rx_s[toggle].rs_hash))) CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock);
is_alt = 0; CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
free(info);
/* RPC could request an earlier block on mainchain */ CTHR_THREAD_RETURN;
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))) { memcpy(main_seedhash, info->seedhash, HASH_SIZE);
randomx_init_cache(cache, seedhash, 32); main_seedhash_set = 1;
rx_sp->rs_cache = cache;
rx_sp->rs_height = seedheight; char buf[HASH_SIZE * 2 + 1];
memcpy(rx_sp->rs_hash, seedhash, sizeof(rx_sp->rs_hash)); hash2hex(main_seedhash, buf);
changed = 1; minfo(RX_LOGCAT, "RandomX new main seed hash is %s", buf);
}
if (rx_vm == NULL) { const randomx_flags flags = enabled_flags() & ~disabled_flags();
randomx_flags flags = RANDOMX_FLAG_DEFAULT; rx_alloc_dataset(flags, &main_dataset, 0);
if (use_rx_jit()) { rx_alloc_cache(flags, &main_cache);
flags |= RANDOMX_FLAG_JIT;
if (!miners) randomx_init_cache(main_cache, info->seedhash, HASH_SIZE);
flags |= RANDOMX_FLAG_SECURE; minfo(RX_LOGCAT, "RandomX main cache initialized");
}
if(!force_software_aes() && check_aes_hw()) CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock);
flags |= RANDOMX_FLAG_HARD_AES;
if (miners) { // From this point, rx_slow_hash can calculate hashes in light mode, but dataset is not initialized yet
CTHR_MUTEX_LOCK(rx_dataset_mutex); me_rx_init_dataset(info->max_threads);
if (rx_dataset == NULL) {
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
if (rx_dataset == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset"); free(info);
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); 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) CTHR_RWLOCK_UNLOCK_READ(main_dataset_lock);
flags |= RANDOMX_FLAG_FULL_MEM; } else {
else { CTHR_RWLOCK_LOCK_READ(main_cache_lock);
miners = 0; // Double check that main_seedhash didn't change
mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset for miner"); 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); CTHR_RWLOCK_UNLOCK_READ(main_cache_lock);
}
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 (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) CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock);
local_abort("Couldn't allocate RandomX VM"); }
} else if (miners) {
CTHR_MUTEX_LOCK(rx_dataset_mutex); CTHR_RWLOCK_LOCK_READ(secondary_cache_lock);
if (rx_dataset != NULL && rx_dataset_height != seedheight) if (is_secondary(seedhash)) {
rx_initdata(cache, miners, seedheight); rx_init_light_vm(flags, &secondary_vm_light, secondary_cache);
CTHR_MUTEX_UNLOCK(rx_dataset_mutex); randomx_calculate_hash(secondary_vm_light, data, length, result_hash);
} else if (changed) { success = 1;
randomx_vm_set_cache(rx_vm, rx_sp->rs_cache); }
} CTHR_RWLOCK_UNLOCK_READ(secondary_cache_lock);
/* 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) { 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) { void me_rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads) {
if (rx_vm != NULL) { miner_thread = value;
randomx_destroy_vm(rx_vm);
rx_vm = NULL; // 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);
}

@ -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); char *hash, int miners, int is_alt);
//extern "C" void me_rx_reorg(const uint64_t split_height); //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 <algorithm> #include <algorithm>
#include <limits> #include <limits>
@ -2103,7 +2103,7 @@ show_my_outputs(string tx_hash_str,
{"blk_height" , tx_blk_height_str}, {"blk_height" , tx_blk_height_str},
{"tx_size" , fmt::format("{:0.4f}", {"tx_size" , fmt::format("{:0.4f}",
static_cast<double>(txd.size) / 1024.0)}, static_cast<double>(txd.size) / 1024.0)},
{"tx_fee" , xmreg::xmr_amount_to_str(txd.fee, "{:0.12f}", true)}, {"tx_fee" , xmreg::xmr_amount_to_str(txd.fee, "{:0.11f}", true)},
{"blk_timestamp" , blk_timestamp}, {"blk_timestamp" , blk_timestamp},
{"delta_time" , age.first}, {"delta_time" , age.first},
{"outputs_no" , static_cast<uint64_t>(txd.output_pub_keys.size())}, {"outputs_no" , static_cast<uint64_t>(txd.output_pub_keys.size())},
@ -2684,7 +2684,7 @@ show_my_outputs(string tx_hash_str,
context["show_inputs"] = show_key_images; context["show_inputs"] = show_key_images;
context["inputs_no"] = static_cast<uint64_t>(inputs.size()); context["inputs_no"] = static_cast<uint64_t>(inputs.size());
context["sum_mixin_xmr"] = xmreg::xmr_amount_to_str( context["sum_mixin_xmr"] = xmreg::xmr_amount_to_str(
sum_mixin_xmr, "{:0.12f}", false); sum_mixin_xmr, "{:0.11f}", false);
uint64_t possible_spending {0}; uint64_t possible_spending {0};
@ -2717,7 +2717,7 @@ show_my_outputs(string tx_hash_str,
} }
context["possible_spending"] = xmreg::xmr_amount_to_str( context["possible_spending"] = xmreg::xmr_amount_to_str(
possible_spending, "{:0.12f}", false); possible_spending, "{:0.11f}", false);
} // if (enable_mixin_guess) } // if (enable_mixin_guess)
@ -5695,17 +5695,29 @@ json_networkinfo()
return j_response; return j_response;
} }
uint64_t fee_estimated {0}; uint64_t per_kb_fee_estimated {0};
// get dynamic fee estimate from last 10 blocks // 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["status"] = "error";
j_response["message"] = "Cant get dynamic fee esimate"; j_response["message"] = "Cant get per kb dynamic fee esimate";
return j_response; 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"] = MempoolStatus::mempool_no.load();
j_info["tx_pool_size_kbytes"] = MempoolStatus::mempool_size.load(); j_info["tx_pool_size_kbytes"] = MempoolStatus::mempool_size.load();
@ -6123,9 +6135,9 @@ construct_tx_context(transaction tx, uint16_t with_ring_signatures = 0)
{"blk_height" , tx_blk_height_str}, {"blk_height" , tx_blk_height_str},
{"tx_blk_height" , tx_blk_height}, {"tx_blk_height" , tx_blk_height},
{"tx_size" , fmt::format("{:0.4f}", tx_size)}, {"tx_size" , fmt::format("{:0.4f}", tx_size)},
{"tx_fee" , xmreg::xmr_amount_to_str(txd.fee, "{:0.12f}", false)}, {"tx_fee" , xmreg::xmr_amount_to_str(txd.fee, "{:0.11f}", false)},
{"tx_fee_micro" , xmreg::xmr_amount_to_str(txd.fee*1e6, "{:0.4f}", false)}, {"tx_fee_micro" , xmreg::xmr_amount_to_str(txd.fee*1e6, "{:0.4f}", false)},
{"payed_for_kB" , fmt::format("{:0.12f}", payed_for_kB)}, {"payed_for_kB" , fmt::format("{:0.11f}", payed_for_kB)},
{"tx_version" , static_cast<uint64_t>(txd.version)}, {"tx_version" , static_cast<uint64_t>(txd.version)},
{"blk_timestamp" , blk_timestamp}, {"blk_timestamp" , blk_timestamp},
{"blk_timestamp_uint" , blk.timestamp}, {"blk_timestamp_uint" , blk.timestamp},
@ -6836,6 +6848,25 @@ get_dynamic_per_kb_fee_estimate(uint64_t& fee_estimated)
return true; 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 bool
are_absolute_offsets_good( are_absolute_offsets_good(
std::vector<uint64_t> const& absolute_offsets, std::vector<uint64_t> const& absolute_offsets,
@ -6947,18 +6978,18 @@ get_randomx_code(uint64_t blk_height,
std::lock_guard<std::mutex> lk {mtx}; std::lock_guard<std::mutex> lk {mtx};
if (!rx_vm) if (!main_vm_full)
{ {
crypto::hash block_hash; crypto::hash block_hash;
// this will create rx_vm instance if one // this will create main_vm_full instance if one
// does not exist // does not exist
me_get_block_longhash(core_storage, blk, block_hash, blk_height, 0); 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 {}; return {};
} }
} }
@ -6969,32 +7000,32 @@ get_randomx_code(uint64_t blk_height,
alignas(16) uint64_t tempHash[8]; alignas(16) uint64_t tempHash[8];
blake2b(tempHash, sizeof(tempHash), bd.data(), bd.size(), nullptr, 0); blake2b(tempHash, sizeof(tempHash), bd.data(), bd.size(), nullptr, 0);
rx_vm->initScratchpad(&tempHash); main_vm_full->initScratchpad(&tempHash);
rx_vm->resetRoundingMode(); main_vm_full->resetRoundingMode();
for (int chain = 0; chain < RANDOMX_PROGRAM_COUNT - 1; ++chain) for (int chain = 0; chain < RANDOMX_PROGRAM_COUNT - 1; ++chain)
{ {
rx_vm->run(&tempHash); main_vm_full->run(&tempHash);
blake2b(tempHash, sizeof(tempHash), blake2b(tempHash, sizeof(tempHash),
rx_vm->getRegisterFile(), main_vm_full->getRegisterFile(),
sizeof(randomx::RegisterFile), nullptr, 0); sizeof(randomx::RegisterFile), nullptr, 0);
rx_code.push_back({}); rx_code.push_back({});
rx_code.back().prog = rx_vm->getProgram(); rx_code.back().prog = main_vm_full->getProgram();
rx_code.back().reg_file = *(rx_vm->getRegisterFile()); rx_code.back().reg_file = *(main_vm_full->getRegisterFile());
} }
rx_vm->run(&tempHash); main_vm_full->run(&tempHash);
rx_code.push_back({}); rx_code.push_back({});
rx_code.back().prog = rx_vm->getProgram(); rx_code.back().prog = main_vm_full->getProgram();
rx_code.back().reg_file = *(rx_vm->getRegisterFile()); rx_code.back().reg_file = *(main_vm_full->getRegisterFile());
//crypto::hash res2; //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; //cout << "pow2: " << pod_to_hex(res2) << endl;
return rx_code; return rx_code;

@ -40,6 +40,33 @@ rpccalls::connect_to_monero_daemon()
return m_http_client.connect(timeout_time_ms); 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 uint64_t
rpccalls::get_current_height() rpccalls::get_current_height()
{ {

@ -86,7 +86,7 @@ public:
using login_opt = boost::optional<epee::net_utils::http::login>; using login_opt = boost::optional<epee::net_utils::http::login>;
rpccalls(string _daemon_url = "http:://127.0.0.1:18081", rpccalls(string _daemon_url = "http:://127.0.0.1:34568",
login_opt _login = login_opt {}, login_opt _login = login_opt {},
uint64_t _timeout = 200000); uint64_t _timeout = 200000);
@ -105,6 +105,9 @@ public:
bool bool
get_network_info(COMMAND_RPC_GET_INFO::response& info); get_network_info(COMMAND_RPC_GET_INFO::response& info);
bool
get_base_fee_estimate(uint64_t grace_blocks, uint64_t& fee_estimate);
bool bool
get_hardfork_info( COMMAND_RPC_HARD_FORK_INFO::response& res); get_hardfork_info( COMMAND_RPC_HARD_FORK_INFO::response& res);

@ -15,7 +15,7 @@
<h4>Output keys for address: {{address}}</h4> <h4>Output keys for address: {{address}}</h4>
<h4>Viewkey: {{viewkey}}</h4> <h4>Viewkey: {{viewkey}}</h4>
{{#has_total_xmr}} {{#has_total_xmr}}
<h4>Total xmr: {{total_xmr}}</h4> <h4>Total wow: {{total_xmr}}</h4>
{{/has_total_xmr}} {{/has_total_xmr}}
<div class="center"> <div class="center">

@ -29,6 +29,7 @@ tr, li, #pages, .info {
td { td {
text-align: center; text-align: center;
word-break: break-all;
} }
a:link { a:link {

@ -2,7 +2,7 @@
<h6 style="margin-top:10px"> <h6 style="margin-top:10px">
<a href="https://github.com/moneroexamples/onion-monero-blockchain-explorer">source code</a> <a href="https://github.com/moneroexamples/onion-monero-blockchain-explorer">source code</a>
| explorer version (api): {{git_branch_name}}-{{last_git_commit_date}}-{{last_git_commit_hash}} ({{api}}) | explorer version (api): {{git_branch_name}}-{{last_git_commit_date}}-{{last_git_commit_hash}} ({{api}})
| monero version: {{monero_version_full}} | wownero version: {{monero_version_full}}
</h6> </h6>
</div> </div>
</body> </body>

@ -18,7 +18,7 @@
<div> <div>
<div class="center"> <div class="center">
<h1 class="center"><a href="/">Onion Monero Blockchain Explorer</a></h1> <h1 class="center"><a href="/">Wownero Blockchain Explorer</a></h1>
<h4 style="font-size: 15px; margin: 0px">(no javascript - no cookies - no web analytics trackers - no images - open sourced)</h4> <h4 style="font-size: 15px; margin: 0px">(no javascript - no cookies - no web analytics trackers - no images - open sourced)</h4>
</div> </div>

@ -55,7 +55,7 @@
{{#emission}} {{#emission}}
<h3 style="font-size: 12px; margin-top: 2px"> <h3 style="font-size: 12px; margin-top: 2px">
Monero emission (fees) is {{amount}} ({{fee_amount}}) as of {{blk_no}} block Wownero emission is {{amount}} ({{fee_amount}}) as of {{blk_no}} block
</h3> </h3>
{{/emission}} {{/emission}}

@ -69,7 +69,7 @@
</table> </table>
<h3> <h3>
Sum XMR from matched outputs (i.e., incoming XMR): Sum WOW from matched outputs (i.e., incoming WOW):
{{#found_our_outputs}} {{#found_our_outputs}}
{{sum_xmr}} {{sum_xmr}}
{{/found_our_outputs}} {{/found_our_outputs}}
@ -142,7 +142,7 @@
</div> </div>
<h3> <h3>
Sum XMR from matched and marked by * ring member's outputs: {{sum_mixin_xmr}} Sum WOW from matched and marked by * ring member's outputs: {{sum_mixin_xmr}}
<br/> <br/>
<span style="font-size: 16px"> Possible spending is: <span style="font-size: 16px"> Possible spending is:
{{possible_spending}} (tx fee included) {{possible_spending}} (tx fee included)
@ -155,7 +155,7 @@
<br/> <br/>
<span style="font-size: 14px"> <span style="font-size: 14px">
Number of possible our mixins is {{no_all_possible_mixins}} Number of possible our mixins is {{no_all_possible_mixins}}
for {{all_possible_mixins_amount}} xmr for {{all_possible_mixins_amount}} wow
(amount as uint64). (amount as uint64).
</span> </span>
</h3> </h3>

@ -55,7 +55,7 @@
</table> </table>
<h3>{{outputs_no}} output(s) for total of {{outputs_xmr_sum}} xmr</h3> <h3>{{outputs_no}} output(s) for total of {{outputs_xmr_sum}} wow</h3>
<div class="center"> <div class="center">
<table class="center"> <table class="center">
<tr> <tr>
@ -83,7 +83,7 @@
<input type="radio" id="tab-1" name="tab-group-1" checked> <input type="radio" id="tab-1" name="tab-group-1" checked>
<label for="tab-1">Decode outputs</label> <label for="tab-1">Decode outputs</label>
<div class="content tab-1"> <div class="content tab-1">
<h4 style="margin: 0px">Check which outputs belong to given Monero address/subaddress and viewkey</h4> <h4 style="margin: 0px">Check which outputs belong to given Wownero address/subaddress and viewkey</h4>
<h5 style="margin: 0px"> <h5 style="margin: 0px">
For RingCT transactions, outputs' amounts are also decoded For RingCT transactions, outputs' amounts are also decoded
<br/> <br/>
@ -91,7 +91,7 @@
</h5> </h5>
<form action="/myoutputs" method="post" style="width:100%; margin-top:2px" class="style-1"> <form action="/myoutputs" method="post" style="width:100%; margin-top:2px" class="style-1">
<input type="hidden" name="tx_hash" value="{{tx_hash}}"><br/> <input type="hidden" name="tx_hash" value="{{tx_hash}}"><br/>
<input type="text" name="xmr_address" size="110" placeholder="Monero address/subaddress"><br/> <input type="text" name="xmr_address" size="110" placeholder="Wownero address/subaddress"><br/>
<input type="text" name="viewkey" size="110" placeholder="Private viewkey" style="margin-top:5px"><br/> <input type="text" name="viewkey" size="110" placeholder="Private viewkey" style="margin-top:5px"><br/>
<input type="hidden" name="raw_tx_data" value="{{raw_tx_data}}"> <input type="hidden" name="raw_tx_data" value="{{raw_tx_data}}">
<!--above raw_tx_data field only used when checking raw tx data through tx pusher--> <!--above raw_tx_data field only used when checking raw tx data through tx pusher-->
@ -105,10 +105,10 @@
<label for="tab-2">Prove sending</label> <label for="tab-2">Prove sending</label>
<div class="content tab-2"> <div class="content tab-2">
<h4 style="margin: 0px">Prove to someone that you have sent them Monero in this transaction</h4> <h4 style="margin: 0px">Prove to someone that you have sent them Wownero in this transaction</h4>
<h5 style="margin: 0px"> <h5 style="margin: 0px">
Tx private key can be obtained using <i>get_tx_key</i> Tx private key can be obtained using <i>get_tx_key</i>
command in <i>monero-wallet-cli</i> command line tool command in <i>wownero-wallet-cli</i> command line tool
<br/> <br/>
Note: address/subaddress and tx private key are sent to the server, as the calculations are done on the server side Note: address/subaddress and tx private key are sent to the server, as the calculations are done on the server side
</h5> </h5>
@ -142,14 +142,14 @@
{{/enable_mixins_details}} {{/enable_mixins_details}}
{{^inputs_xmr_sum_not_zero}} {{^inputs_xmr_sum_not_zero}}
<h3>{{inputs_no}} input(s) for total of {{inputs_xmr_sum}} xmr</h3> <h3>{{inputs_no}} input(s) for total of {{inputs_xmr_sum}} wow</h3>
{{/inputs_xmr_sum_not_zero}} {{/inputs_xmr_sum_not_zero}}
{{#inputs_xmr_sum_not_zero}} {{#inputs_xmr_sum_not_zero}}
{{^have_any_unknown_amount}} {{^have_any_unknown_amount}}
<h3>{{inputs_no}} inputs(s) for total of {{inputs_xmr_sum}} xmr</h3> <h3>{{inputs_no}} inputs(s) for total of {{inputs_xmr_sum}} wow</h3>
{{/have_any_unknown_amount}} {{/have_any_unknown_amount}}
{{#have_any_unknown_amount}} {{#have_any_unknown_amount}}
<h3>{{inputs_no}} inputs(s) for total of at least {{inputs_xmr_sum}} xmr</h3> <h3>{{inputs_no}} inputs(s) for total of at least {{inputs_xmr_sum}} wow</h3>
{{/have_any_unknown_amount}} {{/have_any_unknown_amount}}
{{/inputs_xmr_sum_not_zero}} {{/inputs_xmr_sum_not_zero}}

@ -9,12 +9,12 @@
<div class="center"> <div class="center">
<form action="/checkandpush" method="post" style="width:100%; margin-top:15px" class="style-1"> <form action="/checkandpush" method="post" style="width:100%; margin-top:15px" class="style-1">
Paste here either a hex string of raw transaction<br/> Paste here either a hex string of raw transaction<br/>
(the <i>tx_blob</i> response in the wallet RPC, or the <i>raw_monero_tx</i> (the <i>tx_blob</i> response in the wallet RPC, or the <i>raw_wownero_tx</i>
file saved by the wallet CLI with <i>--do-not-relay</i> option specified),<br/> file saved by the wallet CLI with <i>--do-not-relay</i> option specified),<br/>
or base64 encoded, unsigned or signed transaction data<br/> or base64 encoded, unsigned or signed transaction data<br/>
<br/> <br/>
(In Linux, can get the raw tx data: <i>cat raw_monero_tx | xclip -selection clipboard</i>)<br/> (In Linux, can get the raw tx data: <i>cat raw_wownero_tx | xclip -selection clipboard</i>)<br/>
(In Windows, can get the raw tx data: <i>certutil.exe -encode -f raw_monero_tx encoded.txt & type "encoded.txt" | clip</i>)<br/> (In Windows, can get the raw tx data: <i>certutil.exe -encode -f raw_wownero_tx encoded.txt & type "encoded.txt" | clip</i>)<br/>
<textarea name="rawtxdata" rows="20" cols="80"></textarea> <textarea name="rawtxdata" rows="20" cols="80"></textarea>
<br/> <br/>

@ -627,8 +627,6 @@ sum_fees_in_txs(const vector<transaction>& txs)
return fees_sum; return fees_sum;
} }
vector<output_tuple_with_tag> vector<output_tuple_with_tag>
get_ouputs(const transaction& tx) get_ouputs(const transaction& tx)
{ {

@ -8,7 +8,7 @@
#define PATH_SEPARARTOR '/' #define PATH_SEPARARTOR '/'
#define XMR_AMOUNT(value) \ #define XMR_AMOUNT(value) \
static_cast<double>(value) / 1e12 static_cast<double>(value) / 1e11
#define REMOVE_HASH_BRAKETS(a_hash) \ #define REMOVE_HASH_BRAKETS(a_hash) \
a_hash.substr(1, a_hash.size()-2) a_hash.substr(1, a_hash.size()-2)
@ -228,7 +228,7 @@ get_payment_id(const transaction& tx,
inline double inline double
get_xmr(uint64_t core_amount) get_xmr(uint64_t core_amount)
{ {
return static_cast<double>(core_amount) / 1e12; return static_cast<double>(core_amount) / 1e11;
} }
array<size_t, 5> array<size_t, 5>

Loading…
Cancel
Save