From 10a24bb1a2ed50ed2d5e542c829c9eb827838ad2 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 10 Feb 2025 08:38:53 -0600 Subject: [PATCH] Do not allow replay-blockchain without snapshot unless a full block log is available. --- libraries/chain/block_log.cpp | 25 +++++++++++++++---- .../chain/include/eosio/chain/block_log.hpp | 3 +++ plugins/chain_plugin/chain_plugin.cpp | 5 ++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/libraries/chain/block_log.cpp b/libraries/chain/block_log.cpp index 946e4764b8..c7112f334d 100644 --- a/libraries/chain/block_log.cpp +++ b/libraries/chain/block_log.cpp @@ -510,6 +510,9 @@ namespace eosio { namespace chain { else head = {}; } + + static block_log_preamble extract_block_log_preamble(const std::filesystem::path& block_dir, + const std::filesystem::path& retained_dir); }; // block_log_impl /// Would remove pre-existing block log and index, never write blocks into disk. @@ -1459,8 +1462,8 @@ namespace eosio { namespace chain { } // static - std::optional block_log::extract_chain_context(const std::filesystem::path& block_dir, - const std::filesystem::path& retained_dir) { + block_log_preamble detail::block_log_impl::extract_block_log_preamble(const std::filesystem::path& block_dir, + const std::filesystem::path& retained_dir) { std::filesystem::path first_block_file; if (!retained_dir.empty() && std::filesystem::exists(retained_dir)) { for_each_file_in_dir_matches(retained_dir, R"(blocks-1-\d+\.log)", @@ -1474,9 +1477,9 @@ namespace eosio { namespace chain { } if (!first_block_file.empty()) { - return block_log_data(first_block_file).get_preamble().chain_context; + return block_log_data(first_block_file).get_preamble(); } - + if (!retained_dir.empty() && std::filesystem::exists(retained_dir)) { const std::regex my_filter(R"(blocks-\d+-\d+\.log)"); std::smatch what; @@ -1489,12 +1492,18 @@ namespace eosio { namespace chain { std::string file = p->path().filename().string(); if (!std::regex_match(file, what, my_filter)) continue; - return block_log_data(p->path()).chain_id(); + return block_log_data(p->path()).get_preamble(); } } return {}; } + // static + std::optional block_log::extract_chain_context(const std::filesystem::path& block_dir, + const std::filesystem::path& retained_dir) { + return detail::block_log_impl::extract_block_log_preamble(block_dir, retained_dir).chain_context; + } + // static std::optional block_log::extract_genesis_state(const std::filesystem::path& block_dir, const std::filesystem::path& retained_dir) { @@ -1516,6 +1525,12 @@ namespace eosio { namespace chain { } , *context); } + // static + uint32_t block_log::extract_first_block_num(const std::filesystem::path& block_dir, + const std::filesystem::path& retained_dir) { + return detail::block_log_impl::extract_block_log_preamble(block_dir, retained_dir).first_block_num; + } + // static bool block_log::contains_genesis_state(uint32_t version, uint32_t first_block_num) { return version < genesis_state_or_chain_id_version || first_block_num == 1; diff --git a/libraries/chain/include/eosio/chain/block_log.hpp b/libraries/chain/include/eosio/chain/block_log.hpp index e933cb7920..5bd6196027 100644 --- a/libraries/chain/include/eosio/chain/block_log.hpp +++ b/libraries/chain/include/eosio/chain/block_log.hpp @@ -95,6 +95,9 @@ namespace eosio { namespace chain { extract_chain_id(const std::filesystem::path& data_dir, const std::filesystem::path& retained_dir = std::filesystem::path{}); + static uint32_t extract_first_block_num(const std::filesystem::path& block_dir, + const std::filesystem::path& retained_dir = std::filesystem::path{}); + static void construct_index(const std::filesystem::path& block_file_name, const std::filesystem::path& index_file_name); static bool contains_genesis_state(uint32_t version, uint32_t first_block_num); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index b1c380a2b9..e6143ff266 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -778,6 +778,11 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { ilog( "Replay requested: deleting state database" ); if( options.at( "truncate-at-block" ).as() > 0 ) wlog( "The --truncate-at-block option does not work for a regular replay of the blockchain." ); + if (!options.count( "snapshot" )) { + auto first_block = block_log::extract_first_block_num(blocks_dir, retained_dir); + EOS_ASSERT(first_block == 1, plugin_config_exception, + "replay-blockchain without snapshot requested without a full block log, first block: ${n}", ("n", first_block)); + } clear_directory_contents( chain_config->state_dir ); } else if( options.at( "truncate-at-block" ).as() > 0 ) { wlog( "The --truncate-at-block option can only be used with --hard-replay-blockchain." );