diff options
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 58 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 30 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 28 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_tx_utils.cpp | 3 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 22 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.h | 9 |
6 files changed, 133 insertions, 17 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 87ef47c11..e96dc6bb6 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -156,9 +156,10 @@ static const struct { //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0), - m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false), + m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false), m_difficulty_for_next_block_top_hash(crypto::null_hash), - m_difficulty_for_next_block(1) + m_difficulty_for_next_block(1), + m_btc_valid(false) { LOG_PRINT_L3("Blockchain::" << __func__); } @@ -632,6 +633,7 @@ block Blockchain::pop_block_from_blockchain() update_next_cumulative_size_limit(); m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id()); + invalidate_block_template_cache(); return popped_block; } @@ -642,6 +644,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b) CRITICAL_REGION_LOCAL(m_blockchain_lock); m_timestamps_and_difficulties_height = 0; m_alternative_chains.clear(); + invalidate_block_template_cache(); m_db->reset(); m_hardfork->init(); @@ -1212,9 +1215,26 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m LOG_PRINT_L3("Blockchain::" << __func__); size_t median_size; uint64_t already_generated_coins; + uint64_t pool_cookie; CRITICAL_REGION_BEGIN(m_blockchain_lock); height = m_db->height(); + if (m_btc_valid) { + // The pool cookie is atomic. The lack of locking is OK, as if it changes + // just as we compare it, we'll just use a slightly old template, but + // this would be the case anyway if we'd lock, and the change happened + // just after the block template was created + if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce && m_btc_pool_cookie == m_tx_pool.cookie()) { + MDEBUG("Using cached template"); + m_btc.timestamp = time(NULL); // update timestamp unconditionally + b = m_btc; + diffic = m_btc_difficulty; + expected_reward = m_btc_expected_reward; + 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())); + invalidate_block_template_cache(); + } b.major_version = m_hardfork->get_current_version(); b.minor_version = m_hardfork->get_ideal_version(); @@ -1241,6 +1261,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m { return false; } + pool_cookie = m_tx_pool.cookie(); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) size_t real_txs_size = 0; uint64_t real_fee = 0; @@ -1355,6 +1376,8 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m MDEBUG("Creating block template: miner tx size " << coinbase_blob_size << ", cumulative size " << cumulative_size << " is now good"); #endif + + cache_block_template(b, miner_address, ex_nonce, diffic, expected_reward, pool_cookie); return true; } LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); @@ -2294,7 +2317,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons total_height = get_current_blockchain_height(); size_t count = 0, size = 0; blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height))); - for(size_t i = start_height; i < total_height && count < max_count && (size < FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE || count < 3); i++, count++) + for(uint64_t i = start_height; i < total_height && count < max_count && (size < FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE || count < 3); i++, count++) { blocks.resize(blocks.size()+1); blocks.back().first.first = m_db->get_block_blob_from_height(i); @@ -3697,6 +3720,7 @@ leave: // appears to be a NOP *and* is called elsewhere. wat? m_tx_pool.on_blockchain_inc(new_height, id); get_difficulty_for_next_block(); // just to cache it + invalidate_block_template_cache(); return true; } @@ -3877,11 +3901,13 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) store_blockchain(); m_sync_counter = 0; } - else if (m_db_blocks_per_sync && m_sync_counter >= m_db_blocks_per_sync) + else if (m_db_sync_threshold && ((m_db_sync_on_blocks && m_sync_counter >= m_db_sync_threshold) || (!m_db_sync_on_blocks && m_bytes_to_sync >= m_db_sync_threshold))) { + MDEBUG("Sync threshold met, syncing"); if(m_db_sync_mode == db_async) { m_sync_counter = 0; + m_bytes_to_sync = 0; m_async_service.dispatch(boost::bind(&Blockchain::store_blockchain, this)); } else if(m_db_sync_mode == db_sync) @@ -4073,6 +4099,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete } total_txs += entry.txs.size(); } + m_bytes_to_sync += bytes; while (!(stop_batch = m_db->batch_start(blocks_entry.size(), bytes))) { m_blockchain_lock.unlock(); m_tx_pool.unlock(); @@ -4423,7 +4450,7 @@ bool Blockchain::for_all_txpool_txes(std::function<bool(const crypto::hash&, con return m_db->for_all_txpool_txes(f, include_blob, include_unrelayed_txes); } -void Blockchain::set_user_options(uint64_t maxthreads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync) +void Blockchain::set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync) { if (sync_mode == db_defaultsync) { @@ -4432,7 +4459,8 @@ void Blockchain::set_user_options(uint64_t maxthreads, uint64_t blocks_per_sync, } m_db_sync_mode = sync_mode; m_fast_sync = fast_sync; - m_db_blocks_per_sync = blocks_per_sync; + m_db_sync_on_blocks = sync_on_blocks; + m_db_sync_threshold = sync_threshold; m_max_prepare_blocks_threads = maxthreads; } @@ -4666,6 +4694,24 @@ bool Blockchain::for_all_outputs(uint64_t amount, std::function<bool(uint64_t he return m_db->for_all_outputs(amount, f);; } +void Blockchain::invalidate_block_template_cache() +{ + MDEBUG("Invalidating 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 expected_reward, uint64_t pool_cookie) +{ + MDEBUG("Setting block template cache"); + m_btc = b; + m_btc_address = address; + m_btc_nonce = nonce; + m_btc_difficulty = diff; + m_btc_expected_reward = expected_reward; + m_btc_pool_cookie = pool_cookie; + m_btc_valid = true; +} + namespace cryptonote { template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::vector<transaction>&, std::vector<crypto::hash>&) const; template bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>&, std::vector<cryptonote::blobdata>&, std::vector<crypto::hash>&, bool) const; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index d95c8ed15..2292ffbf3 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -729,11 +729,12 @@ namespace cryptonote * @brief sets various performance options * * @param maxthreads max number of threads when preparing blocks for addition - * @param blocks_per_sync number of blocks to cache before syncing to database + * @param sync_on_blocks whether to sync based on blocks or bytes + * @param sync_threshold number of blocks/bytes to cache before syncing to database * @param sync_mode the ::blockchain_db_sync_mode to use * @param fast_sync sync using built-in block hashes as trusted */ - void set_user_options(uint64_t maxthreads, uint64_t blocks_per_sync, + void set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync); /** @@ -1017,11 +1018,13 @@ namespace cryptonote bool m_fast_sync; bool m_show_time_stats; bool m_db_default_sync; - uint64_t m_db_blocks_per_sync; + bool m_db_sync_on_blocks; + uint64_t m_db_sync_threshold; uint64_t m_max_prepare_blocks_threads; uint64_t m_fake_pow_calc_time; uint64_t m_fake_scan_time; uint64_t m_sync_counter; + uint64_t m_bytes_to_sync; std::vector<uint64_t> m_timestamps; std::vector<difficulty_type> m_difficulties; uint64_t m_timestamps_and_difficulties_height; @@ -1052,6 +1055,15 @@ namespace cryptonote std::atomic<bool> m_cancel; + // block template cache + block m_btc; + account_public_address m_btc_address; + blobdata m_btc_nonce; + difficulty_type m_btc_difficulty; + uint64_t m_btc_pool_cookie; + uint64_t m_btc_expected_reward; + bool m_btc_valid; + /** * @brief collects the keys for all outputs being "spent" as an input * @@ -1407,5 +1419,17 @@ namespace cryptonote * that implicit data. */ bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys); + + /** + * @brief invalidates any cached block template + */ + void invalidate_block_template_cache(); + + /** + * @brief stores a new cached block template + * + * 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 expected_reward, uint64_t pool_cookie); }; } // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 18490c65e..d0db38799 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -439,9 +439,10 @@ namespace cryptonote MGINFO("Loading blockchain from folder " << folder.string() << " ..."); const std::string filename = folder.string(); - // default to fast:async:1 + // default to fast:async:1 if overridden blockchain_db_sync_mode sync_mode = db_defaultsync; - uint64_t blocks_per_sync = 1; + bool sync_on_blocks = true; + uint64_t sync_threshold = 1; if (m_nettype == FAKECHAIN) { @@ -491,7 +492,7 @@ namespace cryptonote else if(options[0] == "fastest") { db_flags = DBF_FASTEST; - blocks_per_sync = 1000; // default to fastest:async:1000 + sync_threshold = 1000; // default to fastest:async:1000 sync_mode = db_sync_mode_is_default ? db_defaultsync : db_async; } else @@ -509,9 +510,22 @@ namespace cryptonote if(options.size() >= 3 && !safemode) { char *endptr; - uint64_t bps = strtoull(options[2].c_str(), &endptr, 0); - if (*endptr == '\0') - blocks_per_sync = bps; + uint64_t threshold = strtoull(options[2].c_str(), &endptr, 0); + if (*endptr == '\0' || !strcmp(endptr, "blocks")) + { + sync_on_blocks = true; + sync_threshold = threshold; + } + else if (!strcmp(endptr, "bytes")) + { + sync_on_blocks = false; + sync_threshold = threshold; + } + else + { + LOG_ERROR("Invalid db sync mode: " << options[2]); + return false; + } } if (db_salvage) @@ -528,7 +542,7 @@ namespace cryptonote } m_blockchain_storage.set_user_options(blocks_threads, - blocks_per_sync, sync_mode, fast_sync); + sync_on_blocks, sync_threshold, sync_mode, fast_sync); const std::pair<uint8_t, uint64_t> regtest_hard_forks[3] = {std::make_pair(1, 0), std::make_pair(Blockchain::get_hard_fork_heights(MAINNET).back().version, 1), std::make_pair(0, 0)}; const cryptonote::test_options regtest_test_options = { diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 071ce591e..1581f3088 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -516,6 +516,7 @@ namespace cryptonote uint64_t amount_in = 0, amount_out = 0; rct::ctkeyV inSk; + inSk.reserve(sources.size()); // mixRing indexing is done the other way round for simple rct::ctkeyM mixRing(use_simple_rct ? sources.size() : n_total_outs); rct::keyV destinations; @@ -532,6 +533,7 @@ namespace cryptonote ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec); ctkey.mask = sources[i].mask; inSk.push_back(ctkey); + memwipe(&ctkey, sizeof(rct::ctkey)); // inPk: (public key, commitment) // will be done when filling in mixRing if (msout) @@ -590,6 +592,7 @@ namespace cryptonote tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof, hwdev); else tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof, hwdev); // same index assumption + memwipe(inSk.data(), inSk.size() * sizeof(rct::ctkey)); CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 3b8dd8107..41c58fcb6 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -102,7 +102,7 @@ namespace cryptonote } //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- - tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_size(DEFAULT_TXPOOL_MAX_SIZE), m_txpool_size(0) + tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_size(DEFAULT_TXPOOL_MAX_SIZE), m_txpool_size(0), m_cookie(0) { } @@ -306,6 +306,8 @@ namespace cryptonote tvc.m_verifivation_failed = false; m_txpool_size += blob_size; + ++m_cookie; + MINFO("Transaction added to pool: txid " << id << " bytes: " << blob_size << " fee/byte: " << (fee / (double)blob_size)); prune(m_txpool_max_size); @@ -341,6 +343,7 @@ namespace cryptonote bytes = m_txpool_max_size; CRITICAL_REGION_LOCAL1(m_blockchain); LockedTXN lock(m_blockchain); + bool changed = false; // this will never remove the first one, but we don't care auto it = --m_txs_by_fee_and_receive_time.end(); @@ -377,6 +380,7 @@ namespace cryptonote remove_transaction_keyimages(tx); MINFO("Pruned tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first); m_txs_by_fee_and_receive_time.erase(it--); + changed = true; } catch (const std::exception &e) { @@ -384,6 +388,8 @@ namespace cryptonote return; } } + if (changed) + ++m_cookie; if (m_txpool_size > bytes) MINFO("Pool size after pruning is larger than limit: " << m_txpool_size << "/" << bytes); } @@ -401,6 +407,7 @@ namespace cryptonote auto ins_res = kei_image_set.insert(id); CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set"); } + ++m_cookie; return true; } //--------------------------------------------------------------------------------- @@ -435,6 +442,7 @@ namespace cryptonote } } + ++m_cookie; return true; } //--------------------------------------------------------------------------------- @@ -480,6 +488,7 @@ namespace cryptonote } m_txs_by_fee_and_receive_time.erase(sorted_it); + ++m_cookie; return true; } //--------------------------------------------------------------------------------- @@ -553,6 +562,7 @@ namespace cryptonote // ignore error } } + ++m_cookie; } return true; } @@ -1051,6 +1061,7 @@ namespace cryptonote { CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL1(m_blockchain); + bool changed = false; LockedTXN lock(m_blockchain); for(size_t i = 0; i!= tx.vin.size(); i++) { @@ -1071,6 +1082,7 @@ namespace cryptonote { MDEBUG("Marking " << txid << " as double spending " << itk.k_image); meta.double_spend_seen = true; + changed = true; try { m_blockchain.update_txpool_tx(txid, meta); @@ -1084,6 +1096,8 @@ namespace cryptonote } } } + if (changed) + ++m_cookie; } //--------------------------------------------------------------------------------- std::string tx_memory_pool::print_pool(bool short_format) const @@ -1299,6 +1313,8 @@ namespace cryptonote } } } + if (n_removed > 0) + ++m_cookie; return n_removed; } //--------------------------------------------------------------------------------- @@ -1355,6 +1371,10 @@ namespace cryptonote } } } + + m_cookie = 0; + + // Ignore deserialization error return true; } diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 4ade7ddbe..4abfef85c 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -362,6 +362,13 @@ namespace cryptonote */ size_t validate(uint8_t version); + /** + * @brief return the cookie + * + * @return the cookie + */ + uint64_t cookie() const { return m_cookie; } + /** * @brief get the cumulative txpool size in bytes * @@ -549,6 +556,8 @@ private: //!< container for transactions organized by fee per size and receive time sorted_tx_container m_txs_by_fee_and_receive_time; + std::atomic<uint64_t> m_cookie; //!< incremented at each change + /** * @brief get an iterator to a transaction in the sorted container * |