From 2e57faf8225e53d2915c988ca6e0b1fc496f4529 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 20 Mar 2025 20:33:34 +0300 Subject: [PATCH 1/4] implemented workaround for rear case when an old node is stuck in an altchain right after the hardfork --- src/currency_core/blockchain_storage.cpp | 56 +++++++++++++++++++++++- src/currency_core/blockchain_storage.h | 2 + src/currency_core/currency_core.cpp | 1 + 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 499b114e..209428d9 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -67,6 +67,7 @@ using namespace currency; #define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //DON'T CHANGE THIS, if you need to resync db change BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION #define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION 4 //mismatch here means some reinitializations #define BLOCKCHAIN_STORAGE_OPTIONS_ID_MAJOR_FAILURE 5 //if not blocks should ever be added with this condition +#define BLOCKCHAIN_STORAGE_OPTIONS_ID_MOST_RECENT_HARDFORK_ID 6 #define TARGETDATA_CACHE_SIZE DIFFICULTY_WINDOW + 10 @@ -95,6 +96,7 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m m_db_storage_major_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION, m_db_solo_options), m_db_storage_minor_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION, m_db_solo_options), m_db_major_failure(BLOCKCHAIN_STORAGE_OPTIONS_ID_MAJOR_FAILURE, m_db_solo_options), + m_db_most_recent_hardfork_id(BLOCKCHAIN_STORAGE_OPTIONS_ID_MOST_RECENT_HARDFORK_ID, m_db_solo_options), m_db_per_block_gindex_incs(m_db), m_tx_pool(tx_pool), m_is_in_checkpoint_zone(false), @@ -116,6 +118,7 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m m_services_mgr.set_core_runtime_config(m_core_runtime_config); m_performance_data.epic_failure_happend = false; } + blockchain_storage::~blockchain_storage() { if (!m_deinit_is_done) @@ -451,7 +454,47 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro m_db.commit_transaction(); LOG_PRINT_MAGENTA("migration of m_db_per_block_gindex_incs completed successfully", LOG_LEVEL_0); } - } + +#ifndef TESTNET + // MAINNET ONLY + if (m_db_most_recent_hardfork_id == 0) + { + // HF5 and the first time use: we need to check + // to handle this case we manually check hash for the block, right after HF5 activation, and if it doesn't match -- truncate the blockchain + block blk{}; + if (get_block_by_height(ZANO_HARDFORK_05_AFTER_HEIGHT + 1, blk)) + { + crypto::hash b3076401_id = epee::string_tools::hex_to_pod("8d93e0a7ab93b367dea44862f27ee9ca044649db84a9f44bf095d2eebc133b2d"); + crypto::hash h = get_block_hash(blk); + if (h != b3076401_id) + { + LOG_PRINT_L0("In the blockchain hash for the block 3076401 is " << h << " while it is expected to be " << b3076401_id << + ". Most likely recent blocks are alternative and invalid for the current hardfork, thus we truncate the blockchain, so that block 3076400 becomes new top block..."); + truncate_blockchain(ZANO_HARDFORK_05_AFTER_HEIGHT + 1); + } + } + else + { + need_reinit = true; + LOG_ERROR("get_block_by_height(" << ZANO_HARDFORK_05_AFTER_HEIGHT + 1 << ") returned false, which is unexpected. Reinit the blockchain."); + } + } + else + { + size_t current_hardfork_id = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(get_top_block_height()); + if (m_db_most_recent_hardfork_id < current_hardfork_id) + { + // most likely we have blocks that don't meet new hardfork criteria, so we need to remove last N blocks till the hardfork and try to resync them again + uint64_t height_right_before_hardfork_activation = m_core_runtime_config.hard_forks.get_height_the_hardfork_active_after(current_hardfork_id); + LOG_PRINT_L0("The most recent hardfork id in the DB is " << m_db_most_recent_hardfork_id << " while according to the code, the top block must belong to the hardfork " << + current_hardfork_id << ". Most likely recent blocks are alternative and invalid for the current hardfork, thus we truncate the blockchain, so that block " << + height_right_before_hardfork_activation << " becomes new top block..."); + truncate_blockchain(height_right_before_hardfork_activation + 1); + } + } +#endif + + } // if (m_db_blocks.size() != 0) if (need_reinit) { @@ -505,9 +548,10 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro set_lost_tx_unmixable(); m_db.commit_transaction(); - LOG_PRINT_GREEN("Blockchain initialized, ver: " << m_db_storage_major_compatibility_version << "." << m_db_storage_minor_compatibility_version << ", last block: " << m_db_blocks.size() - 1 << ENDL + LOG_PRINT_GREEN("Blockchain initialized, ver: " << m_db_storage_major_compatibility_version << "." << m_db_storage_minor_compatibility_version << ENDL << " genesis: " << get_block_hash(m_db_blocks[0]->bl) << ENDL << " last block: " << m_db_blocks.size() - 1 << ", " << misc_utils::get_time_interval_string(timestamp_diff) << " ago" << ENDL + << " last hardfork id: " << m_db_most_recent_hardfork_id << ENDL << " current pos difficulty: " << get_next_diff_conditional(true) << ENDL << " current pow difficulty: " << get_next_diff_conditional(false) << ENDL << " total transactions: " << m_db_transactions.size() << ENDL @@ -579,6 +623,7 @@ void blockchain_storage::store_db_solo_options_values() m_db_storage_major_compatibility_version = BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION; m_db_storage_minor_compatibility_version = BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION; m_db_last_worked_version = std::string(PROJECT_VERSION_LONG); + m_db_most_recent_hardfork_id = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(get_top_block_height()); m_db.commit_transaction(); } //------------------------------------------------------------------ @@ -5380,6 +5425,13 @@ void blockchain_storage::do_full_db_warm_up() const } } //------------------------------------------------------------------ +void blockchain_storage::on_hardfork_activated(size_t hardfork_id) +{ + m_db.begin_transaction(); + m_db_most_recent_hardfork_id = hardfork_id; + m_db.commit_transaction(); +} +//------------------------------------------------------------------ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const { CRITICAL_REGION_LOCAL(m_read_lock); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index aa423cc3..40860074 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -513,6 +513,7 @@ namespace currency void set_db_l2_cache_size(uint64_t ceched_elements) const; //experimental void do_full_db_warm_up() const; + void on_hardfork_activated(size_t hardfork_id); private: @@ -566,6 +567,7 @@ namespace currency tools::db::solo_db_value m_db_storage_major_compatibility_version; tools::db::solo_db_value m_db_storage_minor_compatibility_version; tools::db::solo_db_value m_db_major_failure; //safety fuse + tools::db::solo_db_value m_db_most_recent_hardfork_id; outputs_container m_db_outputs; multisig_outs_container m_db_multisig_outs; diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 37e67e93..e6e04cc4 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -566,6 +566,7 @@ namespace currency if (hardfork_id_for_prev_block != hardfork_id_for_curr_block) { LOG_PRINT_GREEN("Hardfork " << hardfork_id_for_curr_block << " has been activated after the block at height " << h, LOG_LEVEL_0); + m_blockchain_storage.on_hardfork_activated(hardfork_id_for_curr_block); m_pprotocol->on_hardfork_activated(hardfork_id_for_curr_block); } } From ead80ac4cbc2e09fe68f35710b0ed077ef383171 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 21 Mar 2025 14:24:14 +0300 Subject: [PATCH 2/4] improvements for the workaround for rear case when an old node is stuck in an altchain right after the hardfork --- src/currency_core/blockchain_storage.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 209428d9..0d71a151 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -460,7 +460,7 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro if (m_db_most_recent_hardfork_id == 0) { // HF5 and the first time use: we need to check - // to handle this case we manually check hash for the block, right after HF5 activation, and if it doesn't match -- truncate the blockchain + // to handle this case we manually check hash for the block right after HF5 activation, and if it doesn't match -- truncate the blockchain block blk{}; if (get_block_by_height(ZANO_HARDFORK_05_AFTER_HEIGHT + 1, blk)) { @@ -475,16 +475,16 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro } else { - need_reinit = true; - LOG_ERROR("get_block_by_height(" << ZANO_HARDFORK_05_AFTER_HEIGHT + 1 << ") returned false, which is unexpected. Reinit the blockchain."); + // do nothing if there's no such block (yet) } } else { - size_t current_hardfork_id = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(get_top_block_height()); + uint64_t next_block_height = get_top_block_height() + 1; + size_t current_hardfork_id = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(next_block_height); // note: current rules are effective for top_block_height+1 if (m_db_most_recent_hardfork_id < current_hardfork_id) { - // most likely we have blocks that don't meet new hardfork criteria, so we need to remove last N blocks till the hardfork and try to resync them again + // most likely we have blocks that don't meet new hardfork criteria, so we need to remove last N blocks till the hardfork height and try to resync them again uint64_t height_right_before_hardfork_activation = m_core_runtime_config.hard_forks.get_height_the_hardfork_active_after(current_hardfork_id); LOG_PRINT_L0("The most recent hardfork id in the DB is " << m_db_most_recent_hardfork_id << " while according to the code, the top block must belong to the hardfork " << current_hardfork_id << ". Most likely recent blocks are alternative and invalid for the current hardfork, thus we truncate the blockchain, so that block " << @@ -623,7 +623,7 @@ void blockchain_storage::store_db_solo_options_values() m_db_storage_major_compatibility_version = BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION; m_db_storage_minor_compatibility_version = BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION; m_db_last_worked_version = std::string(PROJECT_VERSION_LONG); - m_db_most_recent_hardfork_id = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(get_top_block_height()); + m_db_most_recent_hardfork_id = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(get_top_block_height() + 1 /* <-- next block height */); m_db.commit_transaction(); } //------------------------------------------------------------------ From 78293c32d6493d5516b51ab6a98dc389e73ee720 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 21 Mar 2025 21:38:40 +0400 Subject: [PATCH 3/4] couple tweaks for hf5 transition --- src/currency_core/blockchain_storage.cpp | 1 + src/currency_core/tx_pool.cpp | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 0d71a151..31b607ca 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -471,6 +471,7 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro LOG_PRINT_L0("In the blockchain hash for the block 3076401 is " << h << " while it is expected to be " << b3076401_id << ". Most likely recent blocks are alternative and invalid for the current hardfork, thus we truncate the blockchain, so that block 3076400 becomes new top block..."); truncate_blockchain(ZANO_HARDFORK_05_AFTER_HEIGHT + 1); + m_tx_pool.clear(); } } else diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp index d076d147..4c98db89 100644 --- a/src/currency_core/tx_pool.cpp +++ b/src/currency_core/tx_pool.cpp @@ -238,18 +238,21 @@ namespace currency } TIME_MEASURE_FINISH_PD(check_inputs_time); - if (tx.version > TRANSACTION_VERSION_PRE_HF4) + if (!from_core) { - TIME_MEASURE_START_PD(check_post_hf4_balance); - r = check_tx_balance(tx, id); - CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: balance proof is invalid"); - TIME_MEASURE_FINISH_PD(check_post_hf4_balance); + if (tx.version > TRANSACTION_VERSION_PRE_HF4) + { + TIME_MEASURE_START_PD(check_post_hf4_balance); + r = check_tx_balance(tx, id); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: balance proof is invalid"); + TIME_MEASURE_FINISH_PD(check_post_hf4_balance); - r = process_type_in_variant_container_and_make_sure_its_unique(tx.extra, [&](const asset_descriptor_operation& ado){ + r = process_type_in_variant_container_and_make_sure_its_unique(tx.extra, [&](const asset_descriptor_operation& ado) { asset_op_verification_context avc = { tx, id, ado }; return m_blockchain.validate_asset_operation(avc, m_blockchain.get_current_blockchain_size()); - }, true); - CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: asset operation is invalid"); + }, true); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: asset operation is invalid"); + } } do_insert_transaction(tx, id, blob_size, kept_by_block, tx_fee, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0); From cf3930e86399301507be7be6d4863c2a0174e406 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 21 Mar 2025 23:01:56 +0300 Subject: [PATCH 4/4] === version bump: 2.1.1.392 -> 2.1.2.394 === --- src/version.h.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/version.h.in b/src/version.h.in index a2c99556..5c997eae 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -5,9 +5,9 @@ #define PROJECT_MAJOR_VERSION "2" #define PROJECT_MINOR_VERSION "1" -#define PROJECT_REVISION "1" +#define PROJECT_REVISION "2" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 392 +#define PROJECT_VERSION_BUILD_NO 394 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"