diff options
m--------- | external/unbound | 0 | ||||
-rw-r--r-- | src/common/dns_utils.cpp | 4 | ||||
-rw-r--r-- | src/common/threadpool.cpp | 11 | ||||
-rw-r--r-- | src/common/threadpool.h | 8 | ||||
-rw-r--r-- | src/crypto/rx-slow-hash.c | 50 | ||||
-rw-r--r-- | src/cryptonote_basic/miner.cpp | 10 | ||||
-rw-r--r-- | src/cryptonote_basic/miner.h | 6 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 62 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 8 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 59 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.h | 4 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_tx_utils.cpp | 17 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_tx_utils.h | 1 | ||||
-rw-r--r-- | src/hardforks/hardforks.cpp | 2 | ||||
-rw-r--r-- | src/ringct/rctSigs.cpp | 15 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 26 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 30 | ||||
-rw-r--r-- | tests/core_tests/chaingen.cpp | 6 | ||||
-rwxr-xr-x | tests/functional_tests/functional_tests_rpc.py | 3 | ||||
-rwxr-xr-x | tests/functional_tests/mining.py | 114 | ||||
-rwxr-xr-x | tests/functional_tests/p2p.py | 19 | ||||
-rw-r--r-- | tests/unit_tests/threadpool.cpp | 40 |
22 files changed, 380 insertions, 115 deletions
diff --git a/external/unbound b/external/unbound -Subproject 0f6c0579d66b65f86066e30e7876105ba2775ef +Subproject b26b3136e25ddcb834d7d75ec155b3ddb1522a2 diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index c871177b1..4f4efcd81 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -521,14 +521,14 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std // send all requests in parallel std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); for (size_t n = 0; n < dns_urls.size(); ++n) { tpool.submit(&waiter,[n, dns_urls, &records, &avail, &valid](){ records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]); }); } - waiter.wait(&tpool); + waiter.wait(); size_t cur_index = first_index; do diff --git a/src/common/threadpool.cpp b/src/common/threadpool.cpp index a1737778c..edc87fc48 100644 --- a/src/common/threadpool.cpp +++ b/src/common/threadpool.cpp @@ -120,7 +120,7 @@ threadpool::waiter::~waiter() catch (...) { /* ignore */ } try { - wait(NULL); + wait(); } catch (const std::exception &e) { @@ -128,12 +128,12 @@ threadpool::waiter::~waiter() } } -void threadpool::waiter::wait(threadpool *tpool) { - if (tpool) - tpool->run(true); +bool threadpool::waiter::wait() { + pool.run(true); boost::unique_lock<boost::mutex> lock(mt); while(num) cv.wait(lock); + return !error(); } void threadpool::waiter::inc() { @@ -166,7 +166,8 @@ void threadpool::run(bool flush) { lock.unlock(); ++depth; is_leaf = e.leaf; - e.f(); + try { e.f(); } + catch (const std::exception &ex) { e.wo->set_error(); try { MERROR("Exception in threadpool job: " << ex.what()); } catch (...) {} } --depth; is_leaf = false; diff --git a/src/common/threadpool.h b/src/common/threadpool.h index 91f9fdf47..66b08fece 100644 --- a/src/common/threadpool.h +++ b/src/common/threadpool.h @@ -55,12 +55,16 @@ public: class waiter { boost::mutex mt; boost::condition_variable cv; + threadpool &pool; int num; + bool error_flag; public: void inc(); void dec(); - void wait(threadpool *tpool); //! Wait for a set of tasks to finish. - waiter() : num(0){} + bool wait(); //! Wait for a set of tasks to finish, returns false iff any error + void set_error() noexcept { error_flag = true; } + bool error() const noexcept { return error_flag; } + waiter(threadpool &pool) : pool(pool), num(0), error_flag(false) {} ~waiter(); }; diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c index 1d7f09cab..fa35a32e2 100644 --- a/src/crypto/rx-slow-hash.c +++ b/src/crypto/rx-slow-hash.c @@ -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_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) { int i; 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 s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 : - (height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1); + const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag(); + const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks(); + uint64_t s_height = (height <= seedhash_epoch_blocks+seedhash_epoch_lag) ? 0 : + (height - seedhash_epoch_lag - 1) & ~(seedhash_epoch_blocks-1); return s_height; } void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) { *seedheight = rx_seedheight(height); - *nextheight = rx_seedheight(height + SEEDHASH_EPOCH_LAG); + *nextheight = rx_seedheight(height + get_seedhash_epoch_lag()); } 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, char *hash, int miners, int is_alt) { 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(); rx_state *rx_sp; randomx_cache *cache; diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 34a559b83..29f6dce5a 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -169,7 +169,9 @@ namespace cryptonote 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"); return false; @@ -471,12 +473,12 @@ namespace cryptonote 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++) { 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)) { @@ -572,7 +574,7 @@ namespace cryptonote b.nonce = nonce; 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)) { diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index b23253d4a..df3f56f68 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -47,12 +47,12 @@ namespace cryptonote struct i_miner_handler { 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: ~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(); void on_synchronized(); //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 resume(); void do_print_hashrate(bool do_hr); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 9d4c5a66c..71b32dcf6 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -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 // nor any of the makefiles, howeve. Need to look into whether or not it's // 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__); size_t median_weight; uint64_t already_generated_coins; uint64_t pool_cookie; + seed_hash = crypto::null_hash; + m_tx_pool.lock(); const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); }); 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; height = m_btc_height; expected_reward = m_btc_expected_reward; + seed_height = m_btc_seed_height; + seed_hash = m_btc_seed_hash; 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)); @@ -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 uint64_t from_block_height = cryptonote::get_block_height(prev_block); 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 { 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.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; diffic = get_difficulty_for_next_block(); 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); @@ -1734,16 +1768,16 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, #endif 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; } LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); 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 @@ -3298,8 +3332,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, results.resize(tx.vin.size(), 0); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; - const auto waiter_guard = epee::misc_utils::create_scope_leave_handler([&]() { waiter.wait(&tpool); }); + tools::threadpool::waiter waiter(tpool); int threads = tpool.get_max_concurrency(); uint64_t max_used_block_height = 0; @@ -3369,7 +3402,8 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, sig_index++; } if (tx.version == 1 && threads > 1) - waiter.wait(&tpool); + if (!waiter.wait()) + return false; // enforce min output age if (hf_version >= HF_VERSION_ENFORCE_MIN_AGE) @@ -4908,7 +4942,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete { m_blocks_longhash_table.clear(); uint64_t thread_height = height; - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); m_prepare_height = height; m_prepare_nblocks = blocks_entry.size(); m_prepare_blocks = &blocks; @@ -4921,7 +4955,8 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete thread_height += nblocks; } - waiter.wait(&tpool); + if (!waiter.wait()) + return false; m_prepare_height = 0; if (m_cancel) @@ -5055,14 +5090,15 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete if (threads > 1 && amounts.size() > 1) { - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); for (size_t i = 0; i < amounts.size(); i++) { uint64_t amount = amounts[i]; tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount])), true); } - waiter.wait(&tpool); + if (!waiter.wait()) + return false; } else { @@ -5441,7 +5477,7 @@ void Blockchain::invalidate_block_template_cache() 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"); m_btc = b; @@ -5450,6 +5486,8 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_difficulty = diff; m_btc_height = height; 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_valid = true; } diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 85aa5d4e2..20bd3e5d3 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -366,8 +366,8 @@ namespace cryptonote * * @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 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 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, uint64_t &seed_height, crypto::hash &seed_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_pool_cookie; uint64_t m_btc_expected_reward; + crypto::hash m_btc_seed_hash; + uint64_t m_btc_seed_height; bool m_btc_valid; @@ -1520,6 +1522,6 @@ namespace cryptonote * * 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 diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 474362ed0..fef411a0c 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -226,8 +226,8 @@ namespace cryptonote core::core(i_cryptonote_protocol* pprotocol): m_mempool(m_blockchain_storage), m_blockchain_storage(m_mempool), - m_miner(this, [this](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash) { - return cryptonote::get_block_longhash(&m_blockchain_storage, b, hash, height, threads); + 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, seed_hash, threads); }), m_starter_message_showed(false), m_target_blockchain_height(0), @@ -985,7 +985,7 @@ namespace cryptonote CRITICAL_REGION_LOCAL(m_incoming_tx_lock); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); epee::span<tx_blob_entry>::const_iterator it = tx_blobs.begin(); for (size_t i = 0; i < tx_blobs.size(); i++, ++it) { tpool.submit(&waiter, [&, i, it] { @@ -1001,7 +1001,8 @@ namespace cryptonote } }); } - waiter.wait(&tpool); + if (!waiter.wait()) + return false; it = tx_blobs.begin(); std::vector<bool> already_have(tx_blobs.size(), false); for (size_t i = 0; i < tx_blobs.size(); i++, ++it) { @@ -1033,7 +1034,8 @@ namespace cryptonote }); } } - waiter.wait(&tpool); + if (!waiter.wait()) + return false; std::vector<tx_verification_batch_info> tx_info; tx_info.reserve(tx_blobs.size()); @@ -1182,11 +1184,42 @@ namespace cryptonote 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; + size_t res = 0; if (block_sync_size > 0) - return block_sync_size; - if (height >= quick_height) - return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; - return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4; + res = block_sync_size; + else if (height >= quick_height) + res = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; + 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 @@ -1358,14 +1391,14 @@ namespace cryptonote 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 diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index a53596c2c..c9d26e0ed 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -231,8 +231,8 @@ namespace cryptonote * * @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 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 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, uint64_t &seed_height, crypto::hash &seed_hash); /** * @brief called when a transaction is relayed. diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 7ea7e81d9..7400c4328 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -663,9 +663,9 @@ namespace cryptonote bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; bl.timestamp = 0; bl.nonce = nonce; - miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ - return cryptonote::get_block_longhash(NULL, b, hash, height, threads); - }, bl, 1, 0); + 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, seed_hash, threads); + }, bl, 1, 0, NULL); bl.invalidate_hashes(); 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); } - 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 if (height == 202612) @@ -693,7 +693,7 @@ namespace cryptonote if (pbc != NULL) { 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(); } else { @@ -701,7 +701,7 @@ namespace cryptonote seed_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 { 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); @@ -709,6 +709,11 @@ namespace cryptonote 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 p = crypto::null_hash; diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 3622029e0..dbdf409b5 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -134,6 +134,7 @@ namespace cryptonote 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 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, 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); diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index c94884fd8..6b8c0a8d6 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -93,6 +93,8 @@ const hardfork_t testnet_hard_forks[] = { { 10, 1154318, 0, 1550153694 }, { 11, 1155038, 0, 1550225678 }, { 12, 1308737, 0, 1569582000 }, + { 13, 1543939, 0, 1599069376 }, + { 14, 1544659, 0, 1599069377 }, }; const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); const uint64_t testnet_hard_fork_version_1_till = 624633; diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 5fd7ac06d..93eb52d4e 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -1278,12 +1278,13 @@ namespace rct { { if (semantics) { tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); std::deque<bool> results(rv.outPk.size(), false); DP("range proofs verified?"); for (size_t i = 0; i < rv.outPk.size(); i++) tpool.submit(&waiter, [&, i] { results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); }); - waiter.wait(&tpool); + if (!waiter.wait()) + return false; for (size_t i = 0; i < results.size(); ++i) { if (!results[i]) { @@ -1327,7 +1328,7 @@ namespace rct { PERF_TIMER(verRctSemanticsSimple); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); std::deque<bool> results; std::vector<const Bulletproof*> proofs; size_t max_non_bp_proofs = 0, offset = 0; @@ -1410,7 +1411,8 @@ namespace rct { return false; } - waiter.wait(&tpool); + if (!waiter.wait()) + return false; for (size_t i = 0; i < results.size(); ++i) { if (!results[i]) { LOG_PRINT_L1("Range proof verified failed for proof " << i); @@ -1458,7 +1460,7 @@ namespace rct { std::deque<bool> results(threads); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); const keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts; @@ -1476,7 +1478,8 @@ namespace rct { results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]); }); } - waiter.wait(&tpool); + if (!waiter.wait()) + return false; for (size_t i = 0; i < results.size(); ++i) { if (!results[i]) { diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 36e86ae5d..82e3e9040 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -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) { 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.message = "Internal error: failed to create block template"; @@ -1659,17 +1659,6 @@ namespace cryptonote 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()) { reserved_offset = 0; @@ -1897,9 +1886,16 @@ namespace cryptonote return false; } 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) { - return cryptonote::get_block_longhash(&(m_core.get_blockchain_storage()), b, hash, height, threads); - }, b, template_res.difficulty, template_res.height); + crypto::hash seed_hash = crypto::null_hash; + if (b.major_version >= RX_BLOCK_VERSION && !epee::string_tools::hex_to_pod(template_res.seed_hash, seed_hash)) + { + 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)); r = on_submitblock(submit_req, submit_res, error_resp, ctx); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 359a12bc7..c9289a0b2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1949,7 +1949,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote int num_vouts_received = 0; tx_pub_key = pub_key_field.pub_key; tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); const cryptonote::account_keys& keys = m_account.get_keys(); crypto::key_derivation derivation; @@ -2022,7 +2022,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i, std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true); } - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); // then scan all outputs from 0 hw::device &hwdev = m_account.get_device(); boost::unique_lock<hw::device> hwdev_lock (hwdev); @@ -2049,7 +2049,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i, std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true); } - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); hw::device &hwdev = m_account.get_device(); boost::unique_lock<hw::device> hwdev_lock (hwdev); @@ -2687,7 +2687,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::out_of_hashchain_bounds_error); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); size_t num_txes = 0; std::vector<tx_cache_data> tx_cache_data; @@ -2714,7 +2714,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry } } THROW_WALLET_EXCEPTION_IF(txidx != num_txes, error::wallet_internal_error, "txidx does not match tx_cache_data size"); - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); hw::device &hwdev = m_account.get_device(); hw::reset_mode rst(hwdev); @@ -2743,7 +2743,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry gender(iod); }, true); } - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); auto geniod = [&](const cryptonote::transaction &tx, size_t n_vouts, size_t txidx) { for (size_t k = 0; k < n_vouts; ++k) @@ -2791,7 +2791,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry } } THROW_WALLET_EXCEPTION_IF(txidx != tx_cache_data.size(), error::wallet_internal_error, "txidx did not reach expected value"); - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); hwdev.set_mode(hw::device::NONE); size_t tx_cache_data_offset = 0; @@ -2863,14 +2863,14 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks THROW_WALLET_EXCEPTION_IF(blocks.size() != o_indices.size(), error::wallet_internal_error, "Mismatched sizes of blocks and o_indices"); tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); parsed_blocks.resize(blocks.size()); for (size_t i = 0; i < blocks.size(); ++i) { tpool.submit(&waiter, boost::bind(&wallet2::parse_block_round, this, std::cref(blocks[i].block), std::ref(parsed_blocks[i].block), std::ref(parsed_blocks[i].hash), std::ref(parsed_blocks[i].error)), true); } - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); for (size_t i = 0; i < blocks.size(); ++i) { if (parsed_blocks[i].error) @@ -2896,7 +2896,7 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks }, true); } } - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); last = !blocks.empty() && cryptonote::get_block_height(parsed_blocks.back().block) + 1 == current_height; } catch(...) @@ -3338,7 +3338,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo crypto::hash last_tx_hash_id = m_transfers.size() ? m_transfers.back().m_txid : null_hash; std::list<crypto::hash> short_chain_history; tools::threadpool& tpool = tools::threadpool::getInstance(); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(tpool); uint64_t blocks_start_height; std::vector<cryptonote::block_complete_entry> blocks; std::vector<parsed_block> parsed_blocks; @@ -3446,7 +3446,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo } blocks_fetched += added_blocks; } - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); if(!first && blocks_start_height == next_blocks_start_height) { m_node_rpc_proxy.set_height(m_blockchain.size()); @@ -3478,19 +3478,19 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo catch (const tools::error::password_needed&) { blocks_fetched += added_blocks; - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); throw; } catch (const error::payment_required&) { // no point in trying again, it'd just eat up credits - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); throw; } catch (const std::exception&) { blocks_fetched += added_blocks; - waiter.wait(&tpool); + THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool"); if(try_count < 3) { LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")..."); diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index e8f070214..d1aeef488 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -409,9 +409,9 @@ void test_generator::fill_nonce(cryptonote::block& blk, const difficulty_type& d } blk.nonce = 0; - while (!miner::find_nonce_for_given_block([blockchain](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ - return cryptonote::get_block_longhash(blockchain, b, hash, height, threads); - }, blk, diffic, height)) { + 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, seed_hash, threads); + }, blk, diffic, height, NULL)) { blk.timestamp++; } } diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py index 3be62c0ca..79e04b8a6 100755 --- a/tests/functional_tests/functional_tests_rpc.py +++ b/tests/functional_tests/functional_tests_rpc.py @@ -92,6 +92,9 @@ try: os.environ['PYTHONIOENCODING'] = 'utf-8' os.environ['DIFFICULTY'] = str(DIFFICULTY) 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)): #print('Running: ' + str(command_lines[i])) processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i])) diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py index d067c25e1..c60bf8396 100755 --- a/tests/functional_tests/mining.py +++ b/tests/functional_tests/mining.py @@ -30,6 +30,7 @@ from __future__ import print_function import time +import os """Test daemon mining RPC calls @@ -49,6 +50,8 @@ class MiningTest(): self.mine(True) self.mine(False) self.submitblock() + self.reset() + self.test_randomx() def reset(self): print('Resetting blockchain') @@ -169,6 +172,117 @@ class MiningTest(): assert res.height == height + i + 1 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: def __enter__(self): diff --git a/tests/functional_tests/p2p.py b/tests/functional_tests/p2p.py index f36e9c0b1..0b33411f9 100755 --- a/tests/functional_tests/p2p.py +++ b/tests/functional_tests/p2p.py @@ -139,6 +139,25 @@ class P2PTest(): assert res.height == height + 6 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): print('Testing P2P tx propagation') daemon2 = Daemon(idx = 2) diff --git a/tests/unit_tests/threadpool.cpp b/tests/unit_tests/threadpool.cpp index 1307cd738..1017f04ff 100644 --- a/tests/unit_tests/threadpool.cpp +++ b/tests/unit_tests/threadpool.cpp @@ -34,46 +34,46 @@ TEST(threadpool, wait_nothing) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests()); - tools::threadpool::waiter waiter; - waiter.wait(tpool.get()); + tools::threadpool::waiter waiter(*tpool);; + waiter.wait(); } TEST(threadpool, wait_waits) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests()); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<bool> b(false); tpool->submit(&waiter, [&b](){ epee::misc_utils::sleep_no_w(1000); b = true; }); ASSERT_FALSE(b); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_TRUE(b); } TEST(threadpool, one_thread) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(1)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<unsigned int> counter(0); for (size_t n = 0; n < 4096; ++n) { tpool->submit(&waiter, [&counter](){++counter;}); } - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(counter, 4096); } TEST(threadpool, many_threads) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(256)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<unsigned int> counter(0); for (size_t n = 0; n < 4096; ++n) { tpool->submit(&waiter, [&counter](){++counter;}); } - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(counter, 4096); } @@ -82,44 +82,44 @@ static uint64_t fibonacci(std::shared_ptr<tools::threadpool> tpool, uint64_t n) if (n <= 1) return n; uint64_t f1, f2; - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); tpool->submit(&waiter, [&tpool, &f1, n](){ f1 = fibonacci(tpool, n-1); }); tpool->submit(&waiter, [&tpool, &f2, n](){ f2 = fibonacci(tpool, n-2); }); - waiter.wait(tpool.get()); + waiter.wait(); return f1 + f2; } TEST(threadpool, reentrency) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); uint64_t f = fibonacci(tpool, 13); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(f, 233); } TEST(threadpool, reentrancy) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); uint64_t f = fibonacci(tpool, 13); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(f, 233); } TEST(threadpool, leaf_throws) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests()); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); bool thrown = false, executed = false; tpool->submit(&waiter, [&](){ try { tpool->submit(&waiter, [&](){ executed = true; }); } catch(const std::exception &e) { thrown = true; } }, true); - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_TRUE(thrown); ASSERT_FALSE(executed); } @@ -127,20 +127,20 @@ TEST(threadpool, leaf_throws) TEST(threadpool, leaf_reentrancy) { std::shared_ptr<tools::threadpool> tpool(tools::threadpool::getNewForUnitTests(4)); - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); std::atomic<int> counter(0); for (int i = 0; i < 1000; ++i) { tpool->submit(&waiter, [&](){ - tools::threadpool::waiter waiter; + tools::threadpool::waiter waiter(*tpool); for (int j = 0; j < 500; ++j) { tpool->submit(&waiter, [&](){ ++counter; }, true); } - waiter.wait(tpool.get()); + waiter.wait(); }); } - waiter.wait(tpool.get()); + waiter.wait(); ASSERT_EQ(counter, 500000); } |