Merge pull request #6111

d20ff4f64 functional_tests: add a large (many randomx epochs) p2p reorg test (moneromooo-monero)
6a0b3b1f8 functional_tests: add randomx tests (moneromooo-monero)
9d42649d5 core: fix mining from a block that's not the current top (moneromooo-monero)
This commit is contained in:
Riccardo Spagni 2020-09-06 15:49:36 +02:00
commit aefa7740c3
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
14 changed files with 306 additions and 55 deletions

View file

@ -116,6 +116,46 @@ static inline int enabled_flags(void) {
#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */ #define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */
#define SEEDHASH_EPOCH_LAG 64 #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)
{
static unsigned int lag = (unsigned int)-1;
if (lag != (unsigned int)-1)
return lag;
const char *e = getenv("SEEDHASH_EPOCH_LAG");
if (e)
{
lag = atoi(e);
if (lag > SEEDHASH_EPOCH_LAG || !is_power_of_2(lag))
lag = SEEDHASH_EPOCH_LAG;
}
else
{
lag = SEEDHASH_EPOCH_LAG;
}
return lag;
}
static unsigned int get_seedhash_epoch_blocks(void)
{
static unsigned int blocks = (unsigned int)-1;
if (blocks != (unsigned int)-1)
return blocks;
const char *e = getenv("SEEDHASH_EPOCH_BLOCKS");
if (e)
{
blocks = atoi(e);
if (blocks < 2 || blocks > SEEDHASH_EPOCH_BLOCKS || !is_power_of_2(blocks))
blocks = SEEDHASH_EPOCH_BLOCKS;
}
else
{
blocks = SEEDHASH_EPOCH_BLOCKS;
}
return blocks;
}
void rx_reorg(const uint64_t split_height) { void rx_reorg(const uint64_t split_height) {
int i; int i;
CTHR_MUTEX_LOCK(rx_mutex); CTHR_MUTEX_LOCK(rx_mutex);
@ -130,14 +170,16 @@ void rx_reorg(const uint64_t split_height) {
} }
uint64_t rx_seedheight(const uint64_t height) { uint64_t rx_seedheight(const uint64_t height) {
uint64_t s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 : const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag();
(height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1); const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks();
uint64_t s_height = (height <= seedhash_epoch_blocks+seedhash_epoch_lag) ? 0 :
(height - seedhash_epoch_lag - 1) & ~(seedhash_epoch_blocks-1);
return s_height; return s_height;
} }
void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) { void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) {
*seedheight = rx_seedheight(height); *seedheight = rx_seedheight(height);
*nextheight = rx_seedheight(height + SEEDHASH_EPOCH_LAG); *nextheight = rx_seedheight(height + get_seedhash_epoch_lag());
} }
typedef struct seedinfo { typedef struct seedinfo {
@ -194,7 +236,7 @@ static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_
void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, 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) { char *hash, int miners, int is_alt) {
uint64_t s_height = rx_seedheight(mainheight); uint64_t s_height = rx_seedheight(mainheight);
int toggle = (s_height & SEEDHASH_EPOCH_BLOCKS) != 0; int toggle = (s_height & get_seedhash_epoch_blocks()) != 0;
randomx_flags flags = enabled_flags() & ~disabled_flags(); randomx_flags flags = enabled_flags() & ~disabled_flags();
rx_state *rx_sp; rx_state *rx_sp;
randomx_cache *cache; randomx_cache *cache;

View file

@ -169,7 +169,9 @@ namespace cryptonote
extra_nonce = m_extra_messages[m_config.current_extra_message_index]; extra_nonce = m_extra_messages[m_config.current_extra_message_index];
} }
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce)) uint64_t seed_height;
crypto::hash seed_hash;
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, seed_hash))
{ {
LOG_ERROR("Failed to get_block_template(), stopping mining"); LOG_ERROR("Failed to get_block_template(), stopping mining");
return false; return false;
@ -471,12 +473,12 @@ namespace cryptonote
return true; return true;
} }
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
bool miner::find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height) bool miner::find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height, const crypto::hash *seed_hash)
{ {
for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++) for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
{ {
crypto::hash h; crypto::hash h;
gbh(bl, height, diffic <= 100 ? 0 : tools::get_max_concurrency(), h); gbh(bl, height, seed_hash, diffic <= 100 ? 0 : tools::get_max_concurrency(), h);
if(check_hash(h, diffic)) if(check_hash(h, diffic))
{ {
@ -572,7 +574,7 @@ namespace cryptonote
b.nonce = nonce; b.nonce = nonce;
crypto::hash h; crypto::hash h;
m_gbh(b, height, tools::get_max_concurrency(), h); m_gbh(b, height, NULL, tools::get_max_concurrency(), h);
if(check_hash(h, local_diff)) if(check_hash(h, local_diff))
{ {

View file

@ -47,12 +47,12 @@ namespace cryptonote
struct i_miner_handler struct i_miner_handler
{ {
virtual bool handle_block_found(block& b, block_verification_context &bvc) = 0; virtual bool handle_block_found(block& b, block_verification_context &bvc) = 0;
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) = 0; virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) = 0;
protected: protected:
~i_miner_handler(){}; ~i_miner_handler(){};
}; };
typedef std::function<bool(const cryptonote::block&, uint64_t, unsigned int, crypto::hash&)> get_block_hash_t; typedef std::function<bool(const cryptonote::block&, uint64_t, const crypto::hash*, unsigned int, crypto::hash&)> get_block_hash_t;
/************************************************************************/ /************************************************************************/
/* */ /* */
@ -76,7 +76,7 @@ namespace cryptonote
bool on_idle(); bool on_idle();
void on_synchronized(); void on_synchronized();
//synchronous analog (for fast calls) //synchronous analog (for fast calls)
static bool find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height); static bool find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height, const crypto::hash *seed_hash = NULL);
void pause(); void pause();
void resume(); void resume();
void do_print_hashrate(bool do_hr); void do_print_hashrate(bool do_hr);

View file

@ -1506,13 +1506,15 @@ uint64_t Blockchain::get_current_cumulative_block_weight_median() const
// in a lot of places. That flag is not referenced in any of the code // in a lot of places. That flag is not referenced in any of the code
// nor any of the makefiles, howeve. Need to look into whether or not it's // nor any of the makefiles, howeve. Need to look into whether or not it's
// necessary at all. // necessary at all.
bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
size_t median_weight; size_t median_weight;
uint64_t already_generated_coins; uint64_t already_generated_coins;
uint64_t pool_cookie; uint64_t pool_cookie;
seed_hash = crypto::null_hash;
m_tx_pool.lock(); m_tx_pool.lock();
const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); }); const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); });
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
@ -1531,6 +1533,8 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
diffic = m_btc_difficulty; diffic = m_btc_difficulty;
height = m_btc_height; height = m_btc_height;
expected_reward = m_btc_expected_reward; expected_reward = m_btc_expected_reward;
seed_height = m_btc_seed_height;
seed_hash = m_btc_seed_hash;
return true; return true;
} }
MDEBUG("Not using cached template: address " << (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address))) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block)); MDEBUG("Not using cached template: address " << (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address))) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block));
@ -1564,10 +1568,34 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
CHECK_AND_ASSERT_MES(get_block_by_hash(*from_block, prev_block), false, "From block not found"); // TODO CHECK_AND_ASSERT_MES(get_block_by_hash(*from_block, prev_block), false, "From block not found"); // TODO
uint64_t from_block_height = cryptonote::get_block_height(prev_block); uint64_t from_block_height = cryptonote::get_block_height(prev_block);
height = from_block_height + 1; height = from_block_height + 1;
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
{
uint64_t next_height;
crypto::rx_seedheights(height, &seed_height, &next_height);
seed_hash = get_block_id_by_height(seed_height);
}
} }
else else
{ {
height = alt_chain.back().height + 1; height = alt_chain.back().height + 1;
uint64_t next_height;
crypto::rx_seedheights(height, &seed_height, &next_height);
if (alt_chain.size() && alt_chain.front().height <= seed_height)
{
for (auto it=alt_chain.begin(); it != alt_chain.end(); it++)
{
if (it->height == seed_height+1)
{
seed_hash = it->bl.prev_id;
break;
}
}
}
else
{
seed_hash = get_block_id_by_height(seed_height);
}
} }
b.major_version = m_hardfork->get_ideal_version(height); b.major_version = m_hardfork->get_ideal_version(height);
b.minor_version = m_hardfork->get_ideal_version(); b.minor_version = m_hardfork->get_ideal_version();
@ -1602,6 +1630,12 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
median_weight = m_current_block_cumul_weight_limit / 2; median_weight = m_current_block_cumul_weight_limit / 2;
diffic = get_difficulty_for_next_block(); diffic = get_difficulty_for_next_block();
already_generated_coins = m_db->get_block_already_generated_coins(height - 1); already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
{
uint64_t next_height;
crypto::rx_seedheights(height, &seed_height, &next_height);
seed_hash = get_block_id_by_height(seed_height);
}
} }
b.timestamp = time(NULL); b.timestamp = time(NULL);
@ -1734,16 +1768,16 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
#endif #endif
if (!from_block) if (!from_block)
cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, pool_cookie); cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, seed_height, seed_hash, pool_cookie);
return true; return true;
} }
LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
return false; return false;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
{ {
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce); return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
// for an alternate chain, get the timestamps from the main chain to complete // for an alternate chain, get the timestamps from the main chain to complete
@ -5443,7 +5477,7 @@ void Blockchain::invalidate_block_template_cache()
m_btc_valid = false; m_btc_valid = false;
} }
void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t pool_cookie) void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie)
{ {
MDEBUG("Setting block template cache"); MDEBUG("Setting block template cache");
m_btc = b; m_btc = b;
@ -5452,6 +5486,8 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_
m_btc_difficulty = diff; m_btc_difficulty = diff;
m_btc_height = height; m_btc_height = height;
m_btc_expected_reward = expected_reward; m_btc_expected_reward = expected_reward;
m_btc_seed_hash = seed_hash;
m_btc_seed_height = seed_height;
m_btc_pool_cookie = pool_cookie; m_btc_pool_cookie = pool_cookie;
m_btc_valid = true; m_btc_valid = true;
} }

View file

@ -366,8 +366,8 @@ namespace cryptonote
* *
* @return true if block template filled in successfully, else false * @return true if block template filled in successfully, else false
*/ */
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
/** /**
* @brief checks if a block is known about with a given hash * @brief checks if a block is known about with a given hash
@ -1124,6 +1124,8 @@ namespace cryptonote
uint64_t m_btc_height; uint64_t m_btc_height;
uint64_t m_btc_pool_cookie; uint64_t m_btc_pool_cookie;
uint64_t m_btc_expected_reward; uint64_t m_btc_expected_reward;
crypto::hash m_btc_seed_hash;
uint64_t m_btc_seed_height;
bool m_btc_valid; bool m_btc_valid;
@ -1520,6 +1522,6 @@ namespace cryptonote
* *
* At some point, may be used to push an update to miners * At some point, may be used to push an update to miners
*/ */
void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t pool_cookie); void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie);
}; };
} // namespace cryptonote } // namespace cryptonote

View file

@ -226,8 +226,8 @@ namespace cryptonote
core::core(i_cryptonote_protocol* pprotocol): core::core(i_cryptonote_protocol* pprotocol):
m_mempool(m_blockchain_storage), m_mempool(m_blockchain_storage),
m_blockchain_storage(m_mempool), m_blockchain_storage(m_mempool),
m_miner(this, [this](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash) { m_miner(this, [this](const cryptonote::block &b, uint64_t height, const crypto::hash *seed_hash, unsigned int threads, crypto::hash &hash) {
return cryptonote::get_block_longhash(&m_blockchain_storage, b, hash, height, threads); return cryptonote::get_block_longhash(&m_blockchain_storage, b, hash, height, seed_hash, threads);
}), }),
m_starter_message_showed(false), m_starter_message_showed(false),
m_target_blockchain_height(0), m_target_blockchain_height(0),
@ -1184,11 +1184,42 @@ namespace cryptonote
size_t core::get_block_sync_size(uint64_t height) const size_t core::get_block_sync_size(uint64_t height) const
{ {
static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 1220516 : 0; static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 1220516 : 0;
size_t res = 0;
if (block_sync_size > 0) if (block_sync_size > 0)
return block_sync_size; res = block_sync_size;
if (height >= quick_height) else if (height >= quick_height)
return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; res = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT;
return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4; else
res = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4;
static size_t max_block_size = 0;
if (max_block_size == 0)
{
const char *env = getenv("SEEDHASH_EPOCH_BLOCKS");
if (env)
{
int n = atoi(env);
if (n <= 0)
n = BLOCKS_SYNCHRONIZING_MAX_COUNT;
size_t p = 1;
while (p < (size_t)n)
p <<= 1;
max_block_size = p;
}
else
max_block_size = BLOCKS_SYNCHRONIZING_MAX_COUNT;
}
if (res > max_block_size)
{
static bool warned = false;
if (!warned)
{
MWARNING("Clamping block sync size to " << max_block_size);
warned = true;
}
res = max_block_size;
}
return res;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::are_key_images_spent_in_pool(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const bool core::are_key_images_spent_in_pool(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const
@ -1360,14 +1391,14 @@ namespace cryptonote
m_mempool.set_relayed(epee::to_span(tx_hashes), tx_relay); m_mempool.set_relayed(epee::to_span(tx_hashes), tx_relay);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
{ {
return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce); return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
{ {
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce); return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, bool clip_pruned, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, bool clip_pruned, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const

View file

@ -231,8 +231,8 @@ namespace cryptonote
* *
* @note see Blockchain::create_block_template * @note see Blockchain::create_block_template
*/ */
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce); virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
/** /**
* @brief called when a transaction is relayed. * @brief called when a transaction is relayed.

View file

@ -663,9 +663,9 @@ namespace cryptonote
bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
bl.timestamp = 0; bl.timestamp = 0;
bl.nonce = nonce; bl.nonce = nonce;
miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, const crypto::hash *seed_hash, unsigned int threads, crypto::hash &hash){
return cryptonote::get_block_longhash(NULL, b, hash, height, threads); return cryptonote::get_block_longhash(NULL, b, hash, height, seed_hash, threads);
}, bl, 1, 0); }, bl, 1, 0, NULL);
bl.invalidate_hashes(); bl.invalidate_hashes();
return true; return true;
} }
@ -676,7 +676,7 @@ namespace cryptonote
rx_slow_hash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data, 0, 1); 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) bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const crypto::hash *seed_hash, const int miners)
{ {
// block 202612 bug workaround // block 202612 bug workaround
if (height == 202612) if (height == 202612)
@ -693,7 +693,7 @@ namespace cryptonote
if (pbc != NULL) if (pbc != NULL)
{ {
seed_height = rx_seedheight(height); seed_height = rx_seedheight(height);
hash = pbc->get_pending_block_id_by_height(seed_height); hash = seed_hash ? *seed_hash : pbc->get_pending_block_id_by_height(seed_height);
main_height = pbc->get_current_blockchain_height(); main_height = pbc->get_current_blockchain_height();
} else } else
{ {
@ -701,7 +701,7 @@ namespace cryptonote
seed_height = 0; seed_height = 0;
main_height = 0; main_height = 0;
} }
rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, miners, 0); rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, seed_hash ? 0 : miners, !!seed_hash);
} else { } else {
const int pow_variant = b.major_version >= 7 ? b.major_version - 6 : 0; const int pow_variant = b.major_version >= 7 ? b.major_version - 6 : 0;
crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant, height); crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant, height);
@ -709,6 +709,11 @@ namespace cryptonote
return true; return true;
} }
bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners)
{
return get_block_longhash(pbc, b, res, height, NULL, miners);
}
crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners) crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners)
{ {
crypto::hash p = crypto::null_hash; crypto::hash p = crypto::null_hash;

View file

@ -134,6 +134,7 @@ namespace cryptonote
class Blockchain; class Blockchain;
bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const int miners); bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const int miners);
bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const crypto::hash *seed_hash, const int miners);
void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, 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); 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); crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const int miners);

View file

@ -1642,7 +1642,7 @@ namespace cryptonote
bool core_rpc_server::get_block_template(const account_public_address &address, const crypto::hash *prev_block, const cryptonote::blobdata &extra_nonce, size_t &reserved_offset, cryptonote::difficulty_type &difficulty, uint64_t &height, uint64_t &expected_reward, block &b, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, epee::json_rpc::error &error_resp) bool core_rpc_server::get_block_template(const account_public_address &address, const crypto::hash *prev_block, const cryptonote::blobdata &extra_nonce, size_t &reserved_offset, cryptonote::difficulty_type &difficulty, uint64_t &height, uint64_t &expected_reward, block &b, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, epee::json_rpc::error &error_resp)
{ {
b = boost::value_initialized<cryptonote::block>(); b = boost::value_initialized<cryptonote::block>();
if(!m_core.get_block_template(b, prev_block, address, difficulty, height, expected_reward, extra_nonce)) if(!m_core.get_block_template(b, prev_block, address, difficulty, height, expected_reward, extra_nonce, seed_height, seed_hash))
{ {
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Internal error: failed to create block template"; error_resp.message = "Internal error: failed to create block template";
@ -1659,17 +1659,6 @@ namespace cryptonote
return false; return false;
} }
if (b.major_version >= RX_BLOCK_VERSION)
{
uint64_t next_height;
crypto::rx_seedheights(height, &seed_height, &next_height);
seed_hash = m_core.get_block_id_by_height(seed_height);
if (next_height != seed_height)
next_seed_hash = m_core.get_block_id_by_height(next_height);
else
next_seed_hash = seed_hash;
}
if (extra_nonce.empty()) if (extra_nonce.empty())
{ {
reserved_offset = 0; reserved_offset = 0;
@ -1897,9 +1886,16 @@ namespace cryptonote
return false; return false;
} }
b.nonce = req.starting_nonce; b.nonce = req.starting_nonce;
miner::find_nonce_for_given_block([this](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash) { crypto::hash seed_hash = crypto::null_hash;
return cryptonote::get_block_longhash(&(m_core.get_blockchain_storage()), b, hash, height, threads); if (b.major_version >= RX_BLOCK_VERSION && !epee::string_tools::hex_to_pod(template_res.seed_hash, seed_hash))
}, b, template_res.difficulty, template_res.height); {
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error converting seed hash";
return false;
}
miner::find_nonce_for_given_block([this](const cryptonote::block &b, uint64_t height, const crypto::hash *seed_hash, unsigned int threads, crypto::hash &hash) {
return cryptonote::get_block_longhash(&(m_core.get_blockchain_storage()), b, hash, height, seed_hash, threads);
}, b, template_res.difficulty, template_res.height, &seed_hash);
submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b)); submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b));
r = on_submitblock(submit_req, submit_res, error_resp, ctx); r = on_submitblock(submit_req, submit_res, error_resp, ctx);

View file

@ -409,9 +409,9 @@ void test_generator::fill_nonce(cryptonote::block& blk, const difficulty_type& d
} }
blk.nonce = 0; blk.nonce = 0;
while (!miner::find_nonce_for_given_block([blockchain](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ while (!miner::find_nonce_for_given_block([blockchain](const cryptonote::block &b, uint64_t height, const crypto::hash *seed_hash, unsigned int threads, crypto::hash &hash){
return cryptonote::get_block_longhash(blockchain, b, hash, height, threads); return cryptonote::get_block_longhash(blockchain, b, hash, height, seed_hash, threads);
}, blk, diffic, height)) { }, blk, diffic, height, NULL)) {
blk.timestamp++; blk.timestamp++;
} }
} }

View file

@ -92,6 +92,9 @@ try:
os.environ['PYTHONIOENCODING'] = 'utf-8' os.environ['PYTHONIOENCODING'] = 'utf-8'
os.environ['DIFFICULTY'] = str(DIFFICULTY) os.environ['DIFFICULTY'] = str(DIFFICULTY)
os.environ['MAKE_TEST_SIGNATURE'] = builddir + '/tests/functional_tests/make_test_signature' os.environ['MAKE_TEST_SIGNATURE'] = builddir + '/tests/functional_tests/make_test_signature'
os.environ['SEEDHASH_EPOCH_BLOCKS'] = "8"
os.environ['SEEDHASH_EPOCH_LAG'] = "4"
for i in range(len(command_lines)): for i in range(len(command_lines)):
#print('Running: ' + str(command_lines[i])) #print('Running: ' + str(command_lines[i]))
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i])) processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))

View file

@ -30,6 +30,7 @@
from __future__ import print_function from __future__ import print_function
import time import time
import os
"""Test daemon mining RPC calls """Test daemon mining RPC calls
@ -49,6 +50,8 @@ class MiningTest():
self.mine(True) self.mine(True)
self.mine(False) self.mine(False)
self.submitblock() self.submitblock()
self.reset()
self.test_randomx()
def reset(self): def reset(self):
print('Resetting blockchain') print('Resetting blockchain')
@ -169,6 +172,117 @@ class MiningTest():
assert res.height == height + i + 1 assert res.height == height + i + 1
assert res.hash == block_hash assert res.hash == block_hash
def test_randomx(self):
print("Test RandomX")
daemon = Daemon()
wallet = Wallet()
res = daemon.get_height()
daemon.pop_blocks(res.height - 1)
daemon.flush_txpool()
epoch = int(os.environ['SEEDHASH_EPOCH_BLOCKS'])
lag = int(os.environ['SEEDHASH_EPOCH_LAG'])
address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
# check we can generate blocks, and that the seed hash changes when expected
res = daemon.getblocktemplate(address)
first_seed_hash = res.seed_hash
daemon.generateblocks(address, 1 + lag)
res = daemon.mining_status()
assert res.active == False
assert res.pow_algorithm == 'RandomX'
res = daemon.getblocktemplate(address)
seed_hash = res.seed_hash
t0 = time.time()
daemon.generateblocks(address, epoch - 3)
t0 = time.time() - t0
res = daemon.get_info()
assert res.height == lag + epoch - 1
res = daemon.getblocktemplate(address)
assert seed_hash == res.seed_hash
t0 = time.time()
daemon.generateblocks(address, 1)
t0 = time.time() - t0
res = daemon.get_info()
assert res.height == lag + epoch
daemon.generateblocks(address, 1)
res = daemon.getblocktemplate(address)
assert seed_hash != res.seed_hash
new_seed_hash = res.seed_hash
t0 = time.time()
daemon.generateblocks(address, epoch - 1)
t0 = time.time() - t0
res = daemon.getblocktemplate(address)
assert new_seed_hash == res.seed_hash
daemon.generateblocks(address, 1)
res = daemon.getblocktemplate(address)
assert new_seed_hash != res.seed_hash
new_seed_hash = res.seed_hash
t0 = time.time()
daemon.generateblocks(address, epoch - 1)
t0 = time.time() - t0
res = daemon.getblocktemplate(address)
assert new_seed_hash == res.seed_hash
daemon.generateblocks(address, 1)
res = daemon.getblocktemplate(address)
assert new_seed_hash != res.seed_hash
#print('First mining: ' + str(t0))
# pop all these blocks, and feed them again to monerod
print('Recreating the chain')
res = daemon.get_info()
height = res.height
assert height == lag + epoch * 3 + 1
block_hashes = [x.hash for x in daemon.getblockheadersrange(0, height - 1).headers]
assert len(block_hashes) == height
blocks = []
for i in range(len(block_hashes)):
res = daemon.getblock(height = i)
assert res.block_header.hash == block_hashes[i]
blocks.append(res.blob)
daemon.pop_blocks(height)
res = daemon.get_info()
assert res.height == 1
res = daemon.getblocktemplate(address)
assert first_seed_hash == res.seed_hash
t0 = time.time()
for h in range(len(block_hashes)):
res = daemon.submitblock(blocks[h])
t0 = time.time() - t0
res = daemon.get_info()
assert height == res.height
res = daemon.getblocktemplate(address)
assert new_seed_hash != res.seed_hash
res = daemon.pop_blocks(1)
res = daemon.getblocktemplate(address)
assert new_seed_hash == res.seed_hash
#print('Submit: ' + str(t0))
# start mining from the genesis block again
print('Mining from genesis block again')
res = daemon.get_height()
top_hash = res.hash
res = daemon.getblockheaderbyheight(0)
genesis_block_hash = res.block_header.hash
t0 = time.time()
daemon.generateblocks(address, height - 2, prev_block = genesis_block_hash)
t0 = time.time() - t0
res = daemon.get_info()
assert res.height == height - 1
assert res.top_block_hash == top_hash
#print('Second mining: ' + str(t0))
# that one will cause a huge reorg
print('Adding one to reorg')
res = daemon.generateblocks(address, 1)
assert len(res.blocks) == 1
new_top_hash = res.blocks[0]
res = daemon.get_info()
assert res.height == height
assert res.top_block_hash == new_top_hash
class Guard: class Guard:
def __enter__(self): def __enter__(self):

View file

@ -139,6 +139,25 @@ class P2PTest():
assert res.height == height + 6 assert res.height == height + 6
assert res.top_block_hash == daemon2_top_block_hash assert res.top_block_hash == daemon2_top_block_hash
# disconnect and mine a lot on daemon3
daemon2.out_peers(0)
daemon3.out_peers(0)
res = daemon3.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 500)
# reconnect and wait for sync
daemon2.out_peers(8)
daemon3.out_peers(8)
loops = 100
while True:
res2 = daemon2.get_info()
res3 = daemon3.get_info()
if res2.top_block_hash == res3.top_block_hash:
break
time.sleep(10)
loops -= 1
assert loops >= 0
def test_p2p_tx_propagation(self): def test_p2p_tx_propagation(self):
print('Testing P2P tx propagation') print('Testing P2P tx propagation')
daemon2 = Daemon(idx = 2) daemon2 = Daemon(idx = 2)