diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 4279bb851..ad653d147 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4194,6 +4194,11 @@ bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, ui return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting); } +uint64_t Blockchain::get_earliest_ideal_height_for_version(uint8_t version) const +{ + return m_hardfork->get_earliest_ideal_height_for_version(version); +} + std::map> Blockchain:: get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff) const { return m_db->get_output_histogram(amounts, unlocked, recent_cutoff); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 4090199e6..4598c82e2 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -774,6 +774,11 @@ namespace cryptonote */ bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const; + /** + * @brief returns the earliest block a given version may activate + */ + uint64_t get_earliest_ideal_height_for_version(uint8_t version) const; + /** * @brief remove transactions from the transaction pool (if present) * diff --git a/src/cryptonote_core/blockchain_based_list.cpp b/src/cryptonote_core/blockchain_based_list.cpp index 4fadb9e1c..0654b6ec3 100644 --- a/src/cryptonote_core/blockchain_based_list.cpp +++ b/src/cryptonote_core/blockchain_based_list.cpp @@ -15,10 +15,11 @@ const size_t BLOCKCHAIN_BASED_LISTS_HISTORY_DEPTH = 1000; } -BlockchainBasedList::BlockchainBasedList(const std::string& m_storage_file_name) +BlockchainBasedList::BlockchainBasedList(const std::string& m_storage_file_name, uint64_t first_block_number) : m_storage_file_name(m_storage_file_name) - , m_block_height() + , m_block_height(first_block_number) , m_history_depth() + , m_first_block_number(first_block_number) , m_need_store() { load(); @@ -186,7 +187,7 @@ void BlockchainBasedList::apply_block(uint64_t block_height, const crypto::hash& void BlockchainBasedList::remove_latest_block() { - if (!m_block_height) + if (!m_history_depth) return; m_need_store = true; @@ -197,7 +198,7 @@ void BlockchainBasedList::remove_latest_block() m_history.pop_back(); if (m_history.empty()) - m_block_height = 0; + m_block_height = m_first_block_number; } namespace diff --git a/src/cryptonote_core/blockchain_based_list.h b/src/cryptonote_core/blockchain_based_list.h index ab7f60ad7..f7d29e334 100644 --- a/src/cryptonote_core/blockchain_based_list.h +++ b/src/cryptonote_core/blockchain_based_list.h @@ -33,7 +33,7 @@ class BlockchainBasedList typedef std::list list_history; /// Constructors - BlockchainBasedList(const std::string& file_name); + BlockchainBasedList(const std::string& file_name, uint64_t first_block_number); /// List of tiers const supernode_tier_array& tiers(size_t depth = 0) const; @@ -69,6 +69,7 @@ class BlockchainBasedList uint64_t m_block_height; size_t m_history_depth; std::mt19937_64 m_rng; + uint64_t m_first_block_number; mutable bool m_need_store; }; diff --git a/src/cryptonote_core/stake_transaction_processor.cpp b/src/cryptonote_core/stake_transaction_processor.cpp index b75e9ef56..5d38ef174 100644 --- a/src/cryptonote_core/stake_transaction_processor.cpp +++ b/src/cryptonote_core/stake_transaction_processor.cpp @@ -113,12 +113,29 @@ uint64_t get_transaction_amount(const transaction& tx, const account_public_addr } void StakeTransactionProcessor::init_storages(const std::string& config_dir) +{ + CRITICAL_REGION_LOCAL1(m_storage_lock); + + if (m_storage || m_blockchain_based_list) + throw std::runtime_error("StakeTransactionProcessor storages have been already initialized"); + + m_config_dir = config_dir; +} + +void StakeTransactionProcessor::init_storages_impl() { if (m_storage || m_blockchain_based_list) throw std::runtime_error("StakeTransactionProcessor storages have been already initialized"); - m_storage.reset(new StakeTransactionStorage(config_dir + "/" + STAKE_TRANSACTION_STORAGE_FILE_NAME)); - m_blockchain_based_list.reset(new BlockchainBasedList(config_dir + "/" + BLOCKCHAIN_BASED_LIST_FILE_NAME)); + uint64_t first_block_number = m_blockchain.get_earliest_ideal_height_for_version(config::graft::STAKE_TRANSACTION_PROCESSING_DB_VERSION); + + if (first_block_number) + first_block_number--; + + MCLOG(el::Level::Info, "global", "Initialize stake processing storages. First block height is " << first_block_number); + + m_storage.reset(new StakeTransactionStorage(m_config_dir + "/" + STAKE_TRANSACTION_STORAGE_FILE_NAME, first_block_number)); + m_blockchain_based_list.reset(new BlockchainBasedList(m_config_dir + "/" + BLOCKCHAIN_BASED_LIST_FILE_NAME, first_block_number)); } void StakeTransactionProcessor::process_block_stake_transaction(uint64_t block_index, const block& block, const crypto::hash& block_hash, bool update_storage) @@ -248,24 +265,27 @@ void StakeTransactionProcessor::synchronize() { CRITICAL_REGION_LOCAL1(m_storage_lock); - if (!m_storage || !m_blockchain_based_list) - throw std::runtime_error("StakeTransactionProcessor storages have not been initialized"); - BlockchainDB& db = m_blockchain.get_db(); + uint64_t height = db.height(); + + if (!height || m_blockchain.get_hard_fork_version(height - 1) < config::graft::STAKE_TRANSACTION_PROCESSING_DB_VERSION) + return; + + if (!m_storage || !m_blockchain_based_list) + { + init_storages_impl(); + } + //unroll already processed blocks for alternative chains - try { - uint64_t height = db.height(); - - for (;;) + try + { + while (m_storage->has_last_processed_block()) { size_t stake_tx_count = m_storage->get_tx_count(); uint64_t last_processed_block_index = m_storage->get_last_processed_block_index(); - if (!last_processed_block_index) - break; - if (last_processed_block_index < height) { try @@ -301,24 +321,19 @@ void StakeTransactionProcessor::synchronize() if (first_block_index > m_blockchain_based_list->block_height() + 1) first_block_index = m_blockchain_based_list->block_height() + 1; - static const uint64_t SYNC_DEBUG_LOG_STEP = 10000; + static const uint64_t SYNC_DEBUG_LOG_STEP = 10000; + static const uint64_t MAX_ITERATIONS_COUNT = 10000; - bool need_finalize_log_messages = false; + uint64_t last_block_index = first_block_index, + last_block_index_for_sync = height; - uint64_t last_block_index = first_block_index; + if (last_block_index_for_sync - last_block_index > MAX_ITERATIONS_COUNT) + last_block_index_for_sync = first_block_index + MAX_ITERATIONS_COUNT; - for (uint64_t sync_debug_log_next_index=first_block_index + 1; last_block_index= height) - sync_debug_log_next_index = height - 1; - } + if (last_block_index % SYNC_DEBUG_LOG_STEP == 0 || last_block_index == height - 1) + MCLOG(el::Level::Info, "global", "RTA block sync " << last_block_index << "/" << (height - 1)); try { @@ -340,14 +355,17 @@ void StakeTransactionProcessor::synchronize() if (m_storage->need_store()) m_storage->store(); - if (m_stakes_need_update && m_on_stakes_update) - invoke_update_stakes_handler_impl(last_block_index - 1); + if (last_block_index == height) + { + if (m_stakes_need_update && m_on_stakes_update) + invoke_update_stakes_handler_impl(last_block_index - 1); - if (m_blockchain_based_list_need_update && m_on_blockchain_based_list_update) - invoke_update_blockchain_based_list_handler_impl(last_block_index - first_block_index); + if (m_blockchain_based_list_need_update && m_on_blockchain_based_list_update) + invoke_update_blockchain_based_list_handler_impl(last_block_index - first_block_index); - if (need_finalize_log_messages) - MCLOG(el::Level::Info, "global", "Stake transactions sync OK"); + if (first_block_index != last_block_index) + MCLOG(el::Level::Info, "global", "Stake transactions sync OK"); + } } catch (const std::exception &e) { diff --git a/src/cryptonote_core/stake_transaction_processor.h b/src/cryptonote_core/stake_transaction_processor.h index 4030b50cf..53ad090de 100644 --- a/src/cryptonote_core/stake_transaction_processor.h +++ b/src/cryptonote_core/stake_transaction_processor.h @@ -44,6 +44,7 @@ class StakeTransactionProcessor void invoke_update_blockchain_based_list_handler(bool force = true, size_t depth = 1); private: + void init_storages_impl(); void process_block(uint64_t block_index, const block& block, const crypto::hash& block_hash, bool update_storage = true); void invoke_update_stakes_handler_impl(uint64_t block_index); void invoke_update_blockchain_based_list_handler_impl(size_t depth); @@ -51,6 +52,7 @@ class StakeTransactionProcessor void process_block_blockchain_based_list(uint64_t block_index, const block& block, const crypto::hash& block_hash, bool update_storage = true); private: + std::string m_config_dir; Blockchain& m_blockchain; std::unique_ptr m_storage; std::unique_ptr m_blockchain_based_list; diff --git a/src/cryptonote_core/stake_transaction_storage.cpp b/src/cryptonote_core/stake_transaction_storage.cpp index f10047fd3..c8a22f3bb 100644 --- a/src/cryptonote_core/stake_transaction_storage.cpp +++ b/src/cryptonote_core/stake_transaction_storage.cpp @@ -39,12 +39,13 @@ struct stake_transaction_file_data } -StakeTransactionStorage::StakeTransactionStorage(const std::string& storage_file_name) +StakeTransactionStorage::StakeTransactionStorage(const std::string& storage_file_name, uint64_t first_block_number) : m_storage_file_name(storage_file_name) - , m_last_processed_block_index() + , m_last_processed_block_index(first_block_number) , m_last_processed_block_hashes_count() , m_need_store() , m_supernode_stakes_update_block_number() + , m_first_block_number(first_block_number) { load(); } @@ -87,7 +88,7 @@ void StakeTransactionStorage::add_last_processed_block(uint64_t index, const cry void StakeTransactionStorage::remove_last_processed_block() { - if (!m_last_processed_block_index) + if (!m_last_processed_block_hashes_count) return; m_need_store = true; @@ -107,7 +108,7 @@ void StakeTransactionStorage::remove_last_processed_block() m_stake_txs.clear(); - m_last_processed_block_index = 0; + m_last_processed_block_index = m_first_block_number; } } @@ -144,7 +145,7 @@ void StakeTransactionStorage::update_supernode_stakes(uint64_t block_number) if (block_number == m_supernode_stakes_update_block_number) return; - MDEBUG("Build stakes for block " << block_number); + MCLOG(el::Level::Info, "global", "Build stakes for block " << block_number); m_supernode_stakes.clear(); m_supernode_stake_indexes.clear(); @@ -169,7 +170,7 @@ void StakeTransactionStorage::update_supernode_stakes(uint64_t block_number) obsolete_stake = true; } - MDEBUG("...use stake transaction " << tx.hash << " as " << (obsolete_stake ? "obsolete" : "normal") << " stake transaction "); + MCLOG(el::Level::Info, "global", "...use stake transaction " << tx.hash << " as " << (obsolete_stake ? "obsolete" : "normal") << " stake transaction "); //compute stake validity period @@ -200,7 +201,7 @@ void StakeTransactionStorage::update_supernode_stakes(uint64_t block_number) new_stake.block_height = min_tx_block_height; new_stake.unlock_time = max_tx_block_height - min_tx_block_height; - MDEBUG("...first stake transaction for supernode " << tx.supernode_public_id << ": amount=" << tx.amount << ", tier=" << + MCLOG(el::Level::Info, "global", "...first stake transaction for supernode " << tx.supernode_public_id << ": amount=" << tx.amount << ", tier=" << new_stake.tier << ", validity=[" << min_tx_block_height << ";" << max_tx_block_height << ")"); } @@ -219,7 +220,7 @@ void StakeTransactionStorage::update_supernode_stakes(uint64_t block_number) if (obsolete_stake) continue; //no need to aggregate fields from obsolete stake - MDEBUG("...accumulate stake transaction for supernode " << tx.supernode_public_id << ": amount=" << tx.amount << + MCLOG(el::Level::Info, "global", "...accumulate stake transaction for supernode " << tx.supernode_public_id << ": amount=" << tx.amount << ", validity=[" << min_tx_block_height << ";" << max_tx_block_height << ")"); supernode_stake& stake = m_supernode_stakes[it->second]; @@ -258,7 +259,7 @@ void StakeTransactionStorage::update_supernode_stakes(uint64_t block_number) stake.block_height = min_block_height; stake.unlock_time = max_block_height - min_block_height; - MDEBUG("...stake for supernode " << tx.supernode_public_id << ": amount=" << stake.amount << ", tier=" << stake.tier << + MCLOG(el::Level::Info, "global", "...stake for supernode " << tx.supernode_public_id << ": amount=" << stake.amount << ", tier=" << stake.tier << ", validity=[" << min_block_height << ";" << max_block_height << ")"); } } diff --git a/src/cryptonote_core/stake_transaction_storage.h b/src/cryptonote_core/stake_transaction_storage.h index 33321fe1d..e60d8e059 100644 --- a/src/cryptonote_core/stake_transaction_storage.h +++ b/src/cryptonote_core/stake_transaction_storage.h @@ -53,7 +53,7 @@ class StakeTransactionStorage typedef std::list block_hash_list; typedef std::vector supernode_stake_array; - StakeTransactionStorage(const std::string& storage_file_name); + StakeTransactionStorage(const std::string& storage_file_name, uint64_t first_block_number); /// Get number of transactions size_t get_tx_count() const { return m_stake_txs.size(); } @@ -67,6 +67,9 @@ class StakeTransactionStorage /// Get array of last block hashes const crypto::hash& get_last_processed_block_hash() const; + /// Has last processed blocks + bool has_last_processed_block() const { return m_last_processed_block_hashes_count > 0; } + /// Add new processed block void add_last_processed_block(uint64_t index, const crypto::hash& hash); @@ -109,6 +112,7 @@ class StakeTransactionStorage uint64_t m_supernode_stakes_update_block_number; supernode_stake_array m_supernode_stakes; supernode_stake_index_map m_supernode_stake_indexes; + uint64_t m_first_block_number; mutable bool m_need_store; };