From fb184746225713c42a1ffbc578b45834de91edf7 Mon Sep 17 00:00:00 2001 From: canepat <16927169+canepat@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:58:59 +0200 Subject: [PATCH] api: export silkworm_add_snapshot C API to add chain snapshots (#1379) api: use error codes everywhere in C API node: add subset of snapshots altogether in snapshot repository --- cmd/api/CMakeLists.txt | 3 - cmd/api/execute.c | 110 ------------------------ cmd/api/execute.cpp | 96 ++++++++++++++++++++- silkworm/api/silkworm_api.cpp | 117 +++++++++++++++++++++----- silkworm/api/silkworm_api.h | 88 +++++++++++++------ silkworm/node/snapshot/repository.cpp | 10 +++ silkworm/node/snapshot/repository.hpp | 11 +++ 7 files changed, 271 insertions(+), 164 deletions(-) delete mode 100644 cmd/api/execute.c diff --git a/cmd/api/CMakeLists.txt b/cmd/api/CMakeLists.txt index d991e8c146..063dfcd922 100644 --- a/cmd/api/CMakeLists.txt +++ b/cmd/api/CMakeLists.txt @@ -17,9 +17,6 @@ find_package(Boost REQUIRED) find_package(CLI11 REQUIRED) -# add_executable(execute execute.c) target_include_directories(execute PUBLIC ${CMAKE_SOURCE_DIR} -# "${SILKWORM_MAIN_DIR}/third_party/libmdbx") - add_executable(execute_cpp execute.cpp) target_include_directories(execute_cpp PUBLIC ${CMAKE_SOURCE_DIR} "${SILKWORM_MAIN_DIR}/third_party/libmdbx") target_link_libraries(execute_cpp PRIVATE Boost::headers Boost::filesystem Boost::system CLI11::CLI11 silkworm_node) diff --git a/cmd/api/execute.c b/cmd/api/execute.c deleted file mode 100644 index aae50d25f1..0000000000 --- a/cmd/api/execute.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright 2023 The Silkworm Authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include - -#ifdef __APPLE__ -#include -#include -#endif // __APPLE__ - -#include - -const char* kSilkwormApiPath = "libsilkworm_api.so"; -const char* kSilkwormExecuteBlocksSymbol = "_silkworm_execute_blocks"; - -typedef enum SilkwormStatusCode (*SilkwormExecuteBlocksPtr)( - MDBX_txn* txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block, - uint64_t batch_size, bool write_receipts, uint64_t* last_executed_block, - int* mdbx_error_code); // Function pointer for Silkworm execute_blocks API - -#ifdef __APPLE__ -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 -int main_macos(void) { - return 0; -} -#else // __MAC_OS_X_VERSION_MAX_ALLOWED < 1050 -int main_macos(void) { - NSObjectFileImage img; // Represents the bundle's object file - NSModule handle; // Handle to the loaded bundle - NSSymbol sym; // Represents a symbol in the bundle - SilkwormExecuteBlocksPtr silkworm_execute_blocks; - - /* Get an object file for the bundle. */ - const NSObjectFileImageReturnCode rc = NSCreateObjectFileImageFromFile(kSilkwormApiPath, &img); - if (rc != NSObjectFileImageSuccess) { - fprintf(stderr, "Could not load %s.\n", kSilkwormApiPath); - return -1; - } - - /* Get a handle for the bundle. */ - handle = NSLinkModule(img, kSilkwormApiPath, FALSE); - - /* Look up the silkworm_execute_blocks function. */ - sym = NSLookupSymbolInModule(handle, kSilkwormExecuteBlocksSymbol); - if (sym == NULL) { - fprintf(stderr, "Could not find symbol: %s.\n", kSilkwormExecuteBlocksSymbol); - return -2; - } - - /* Get the address of the function. */ - silkworm_execute_blocks = (SilkwormExecuteBlocksPtr)NSAddressOfSymbol(sym); - if (silkworm_execute_blocks == NULL) { - fprintf(stderr, "Could not get address of symbol: %s.\n", kSilkwormExecuteBlocksSymbol); - return -3; - } - - /* Invoke the function. */ - uint64_t last_executed_block; - int mdbx_error_code; - enum SilkwormStatusCode status_code = - silkworm_execute_blocks(NULL, 1, 0, 0, 1, false, &last_executed_block, &mdbx_error_code); - if (status_code != kSilkwormSuccess) { - fprintf(stderr, "Execution failed: %d\n", (int)status_code); - return -4; - } - - return 0; -} -#endif // __MAC_OS_X_VERSION_MAX_ALLOWED < 1050 -#endif // __APPLE__ - -#ifdef _WIN32 -int main_win() { - return 0; -} -#endif // _WIN32 - -#ifdef __linux__ -int main_linux() { - return 0; -} -#endif // __linux__ - -int main(int argc, char* argv[]) { - if (argc > 1) { - const char* argv1 = argv[1]; - printf("argv1=%s\n", argv1); - } - -#if defined __APPLE__ - return main_macos(); -#elif defined _WIN32 - return main_win(); -#elif defined __linux__ - return main_linux(); -#endif -} diff --git a/cmd/api/execute.cpp b/cmd/api/execute.cpp index c58c5b0a49..6fc3db6615 100644 --- a/cmd/api/execute.cpp +++ b/cmd/api/execute.cpp @@ -34,11 +34,27 @@ #include const char* kSilkwormApiLibPath = "../../silkworm/api/libsilkworm_api.dylib"; +const char* kSilkwormInitSymbol = "silkworm_init"; +const char* kSilkwormAddSnapshotSymbol = "silkworm_add_snapshot"; const char* kSilkwormExecuteBlocksSymbol = "silkworm_execute_blocks"; +const char* kSilkwormFiniSymbol = "silkworm_fini"; + +//! Function signature for silkworm_init C API +using SilkwormInitSig = int(SilkwormHandle**); + +//! Function signature for silkworm_add_snapshot C API +using SilkwormAddSnapshotSig = int(SilkwormHandle*, SilkwormChainSnapshot*); //! Function signature for silkworm_execute_blocks C API using SilkwormExecuteBlocksSig = - SilkwormStatusCode(MDBX_txn*, uint64_t, uint64_t, uint64_t, uint64_t, bool, uint64_t*, int*); + int(SilkwormHandle*, MDBX_txn*, uint64_t, uint64_t, uint64_t, uint64_t, bool, uint64_t*, int*); + +//! Function signature for silkworm_fini C API +using SilkwormFiniSig = int(SilkwormHandle*); + +constexpr const char* kHeader1{"/Users/tullio/Library/Silkworm/snapshots/v1-000000-000500-headers.seg"}; +constexpr const char* kBody1{"/Users/tullio/Library/Silkworm/snapshots/v1-000000-000500-bodies.seg"}; +constexpr const char* kTransaction1{"/Users/tullio/Library/Silkworm/snapshots/v1-000000-000500-transactions.seg"}; int main(int /*argc*/, char* /*argv*/[]) { CLI::App app{"Execute blocks"}; @@ -48,10 +64,75 @@ int main(int /*argc*/, char* /*argv*/[]) { std::cout << "Execute blocks starting [pid=" << std::to_string(pid) << "]\n"; // parse_command_line(argc, argv, app, settings); + // Import the silkworm_init symbol from silkworm API library + const auto silkworm_init{ + boost::dll::import_symbol(kSilkwormApiLibPath, kSilkwormInitSymbol)}; + + // Import the silkworm_add_snapshot symbol from silkworm API library + const auto silkworm_add_snapshot{ + boost::dll::import_symbol(kSilkwormApiLibPath, kSilkwormAddSnapshotSymbol)}; + // Import the silkworm_execute_blocks symbol from silkworm API library const auto silkworm_execute_blocks{ boost::dll::import_symbol(kSilkwormApiLibPath, kSilkwormExecuteBlocksSymbol)}; + // Import the silkworm_fini symbol from silkworm API library + const auto silkworm_fini{ + boost::dll::import_symbol(kSilkwormApiLibPath, kSilkwormFiniSymbol)}; + + // Initialize SilkwormAPI library + SilkwormHandle* handle{nullptr}; + const int init_status_code = silkworm_init(&handle); + if (init_status_code != SILKWORM_OK) { + std::cerr << "Execute blocks silkworm_init failed [code=" << std::to_string(init_status_code) << "]\n"; + return init_status_code; + } + + // Add snapshots to SilkwormAPI library + SilkwormChainSnapshot chain_snapshot{ + .headers{ + .segment{ + .file_path = kHeader1, + .memory_address = 0, + .memory_length = 0, + }, + .header_hash_index{ + .file_path = "", + .memory_address = 0, + .memory_length = 0, + }}, + .bodies{ + .segment{ + .file_path = kBody1, + .memory_address = 0, + .memory_length = 0, + }, + .block_num_index{ + .file_path = "", + .memory_address = 0, + .memory_length = 0, + }}, + .transactions{ + .segment{ + .file_path = kTransaction1, + .memory_address = 0, + .memory_length = 0, + }, + .tx_hash_index{ + .file_path = "", + .memory_address = 0, + .memory_length = 0, + }, + .tx_hash_2_block_index{ + .file_path = "", + .memory_address = 0, + .memory_length = 0, + }}}; + const int add_snapshot_status_code{silkworm_add_snapshot(handle, &chain_snapshot)}; + if (add_snapshot_status_code != SILKWORM_OK) { + return init_status_code; + } + silkworm::DataDirectory data_dir{}; silkworm::db::EnvConfig config{ .path = data_dir.chaindata().path().string(), @@ -62,10 +143,19 @@ int main(int /*argc*/, char* /*argv*/[]) { uint64_t last_executed_block{std::numeric_limits::max()}; int mdbx_error_code{0}; - const auto status_code{ - silkworm_execute_blocks(&*rw_txn, 1, 1, 1, 1, false, &last_executed_block, &mdbx_error_code)}; + const int status_code{ + silkworm_execute_blocks(handle, &*rw_txn, 1, 46147, 46147, 1, false, &last_executed_block, &mdbx_error_code)}; std::cout << "Execute blocks status code: " << std::to_string(status_code) << "\n"; + // Finalize SilkwormAPI library + const int fini_status_code = silkworm_fini(handle); + if (fini_status_code != SILKWORM_OK) { + std::cerr << "Execute blocks silkworm_fini failed [code=" << std::to_string(fini_status_code) << "]\n"; + return fini_status_code; + } + + rw_txn.abort(); // We do not want to commit anything now + std::cout << "Execute blocks exiting [pid=" << std::to_string(pid) << "]\n"; return status_code; } catch (const CLI::ParseError& pe) { diff --git a/silkworm/api/silkworm_api.cpp b/silkworm/api/silkworm_api.cpp index 098c6b3952..48bc829810 100644 --- a/silkworm/api/silkworm_api.cpp +++ b/silkworm/api/silkworm_api.cpp @@ -16,11 +16,9 @@ #include "silkworm_api.h" -#include +#include #include -#include - #include #include #include @@ -53,20 +51,89 @@ class RWTxnUnmanaged : public RWTxn, protected ::mdbx::txn { } // namespace silkworm::db -SILKWORM_EXPORT -SilkwormStatusCode silkworm_execute_blocks(MDBX_txn* mdbx_txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block, - uint64_t batch_size, bool write_receipts, uint64_t* last_executed_block, - int* mdbx_error_code) SILKWORM_NOEXCEPT { - assert(mdbx_txn); +using namespace silkworm; + +SILKWORM_EXPORT int silkworm_init(SilkwormHandle** handle) SILKWORM_NOEXCEPT { + if (!handle) { + return SILKWORM_INVALID_HANDLE; + } + const auto snapshot_repository = new snapshot::SnapshotRepository{}; + db::DataModel::set_snapshot_repository(snapshot_repository); + *handle = reinterpret_cast(snapshot_repository); + return SILKWORM_OK; +} - using namespace silkworm; +SILKWORM_EXPORT int silkworm_add_snapshot(SilkwormHandle* handle, SilkwormChainSnapshot* snapshot) SILKWORM_NOEXCEPT { + if (!handle) { + return SILKWORM_INVALID_HANDLE; + } + if (!snapshot) { + return SILKWORM_INVALID_SNAPSHOT; + } + const auto snapshot_repository = reinterpret_cast(handle); + const SilkwormHeadersSnapshot& headers_snapshot = snapshot->headers; + const auto headers_segment_path = snapshot::SnapshotPath::parse(headers_snapshot.segment.file_path); + if (!headers_segment_path) { + return SILKWORM_INVALID_PATH; + } + // TODO(canepat) HeaderSnapshot must be created w/ segment_address+segment_length because mmap already done by Erigon + // TODO(canepat) The same holds for its index + auto headers_segment = std::make_unique( + headers_segment_path->path(), headers_segment_path->block_from(), headers_segment_path->block_to()); + headers_segment->reopen_segment(); // TODO(canepat) must not be called hence throw exception if called when snapshot already mapped + headers_segment->reopen_index(); // TODO(canepat) must not be called hence throw exception if called when snapshot already mapped + + const SilkwormBodiesSnapshot& bodies_snapshot = snapshot->bodies; + const auto bodies_segment_path = snapshot::SnapshotPath::parse(bodies_snapshot.segment.file_path); + if (!bodies_segment_path) { + return SILKWORM_INVALID_PATH; + } + // TODO(canepat) BodySnapshot must be created w/ segment_address+segment_length because mmap already done by Erigon + // TODO(canepat) The same holds for its index + auto bodies_segment = std::make_unique( + bodies_segment_path->path(), bodies_segment_path->block_from(), bodies_segment_path->block_to()); + bodies_segment->reopen_segment(); // TODO(canepat) must not be called hence throw exception if called when snapshot already mapped + bodies_segment->reopen_index(); // TODO(canepat) must not be called hence throw exception if called when snapshot already mapped + + const SilkwormTransactionsSnapshot& transactions_snapshot = snapshot->transactions; + const auto transactions_segment_path = snapshot::SnapshotPath::parse(transactions_snapshot.segment.file_path); + if (!transactions_segment_path) { + return SILKWORM_INVALID_PATH; + } + // TODO(canepat) TransactionSnapshot must be created w/ segment_address+segment_length because mmap already done by Erigon + // TODO(canepat) The same holds for its index + auto transactions_segment = std::make_unique( + transactions_segment_path->path(), transactions_segment_path->block_from(), transactions_segment_path->block_to()); + transactions_segment->reopen_segment(); // TODO(canepat) must not be called hence throw exception if called when snapshot already mapped + transactions_segment->reopen_index(); // TODO(canepat) must not be called hence throw exception if called when snapshot already mapped + + snapshot::SnapshotBundle bundle{ + .headers_snapshot_path = *headers_segment_path, + .headers_snapshot = std::move(headers_segment), + .bodies_snapshot_path = *bodies_segment_path, + .bodies_snapshot = std::move(bodies_segment), + .tx_snapshot_path = *transactions_segment_path, + .tx_snapshot = std::move(transactions_segment)}; + snapshot_repository->add_snapshot_bundle(std::move(bundle)); + return SILKWORM_OK; +} + +SILKWORM_EXPORT +int silkworm_execute_blocks(SilkwormHandle* handle, MDBX_txn* mdbx_txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block, + uint64_t batch_size, bool write_receipts, uint64_t* last_executed_block, int* mdbx_error_code) SILKWORM_NOEXCEPT { + if (!handle) { + return SILKWORM_INVALID_HANDLE; + } + if (!mdbx_txn) { + return SILKWORM_INVALID_MDBX_TXN; + } if (start_block > max_block) { - return kSilkwormInvalidBlockRange; + return SILKWORM_INVALID_BLOCK_RANGE; } const auto chain_info = lookup_known_chain(chain_id); if (!chain_info) { - return kSilkwormUnknownChainId; + return SILKWORM_UNKNOWN_CHAIN_ID; } const ChainConfig* chain_config{chain_info->second}; @@ -74,11 +141,6 @@ SilkwormStatusCode silkworm_execute_blocks(MDBX_txn* mdbx_txn, uint64_t chain_id // Wrap MDBX txn into an internal *unmanaged* txn, i.e. MDBX txn is only used but neither aborted nor committed db::RWTxnUnmanaged txn{mdbx_txn}; - // TODO(txn and snapshot+index memory-mapped files in silkworm_init API) - snapshot::SnapshotRepository snapshot_repo; - snapshot_repo.reopen_folder(); - db::DataModel::set_snapshot_repository(&snapshot_repo); - db::Buffer state_buffer{txn, /*prune_history_threshold=*/0}; db::DataModel access_layer{txn}; @@ -93,7 +155,7 @@ SilkwormStatusCode silkworm_execute_blocks(MDBX_txn* mdbx_txn, uint64_t chain_id prefetched_blocks.emplace_back(); const bool success{access_layer.read_block(block_number, /*read_senders=*/true, prefetched_blocks.back())}; if (!success) { - return kSilkwormBlockNotFound; + return SILKWORM_BLOCK_NOT_FOUND; } } @@ -103,7 +165,7 @@ SilkwormStatusCode silkworm_execute_blocks(MDBX_txn* mdbx_txn, uint64_t chain_id std::vector receipts; const auto validation_result{execute_block(block, state_buffer, *chain_config, receipts)}; if (validation_result != ValidationResult::kOk) { - return kSilkwormInvalidBlock; + return SILKWORM_INVALID_BLOCK; } if (write_receipts) { @@ -131,18 +193,27 @@ SilkwormStatusCode silkworm_execute_blocks(MDBX_txn* mdbx_txn, uint64_t chain_id } state_buffer.write_to_db(); - return kSilkwormSuccess; + return SILKWORM_OK; } catch (const mdbx::exception& e) { if (mdbx_error_code) { *mdbx_error_code = e.error().code(); } - return kSilkwormMdbxError; + return SILKWORM_MDBX_ERROR; } catch (const DecodingError&) { - return kSilkwormDecodingError; + return SILKWORM_DECODING_ERROR; } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what(); - return kSilkwormUnknownError; + return SILKWORM_INTERNAL_ERROR; } catch (...) { - return kSilkwormUnknownError; + return SILKWORM_UNKNOWN_ERROR; + } +} + +SILKWORM_EXPORT int silkworm_fini(SilkwormHandle* handle) SILKWORM_NOEXCEPT { + const auto snapshot_repository = reinterpret_cast(handle); + if (!snapshot_repository) { + return SILKWORM_INVALID_HANDLE; } + delete snapshot_repository; + return SILKWORM_OK; } diff --git a/silkworm/api/silkworm_api.h b/silkworm/api/silkworm_api.h index f8eaea6f42..a17a630a87 100644 --- a/silkworm/api/silkworm_api.h +++ b/silkworm/api/silkworm_api.h @@ -43,43 +43,81 @@ extern "C" { #endif -enum SilkwormStatusCode { - kSilkwormSuccess = 0, - kSilkwormInvalidBlockRange = 1, - kSilkwormBlockNotFound = 2, - kSilkwormUnknownChainId = 3, - kSilkwormMdbxError = 4, - kSilkwormInvalidBlock = 5, - kSilkwormDecodingError = 6, - kSilkwormUnknownError = -1 +#define SILKWORM_OK 0 /* Successful result */ +#define SILKWORM_INTERNAL_ERROR 1 +#define SILKWORM_UNKNOWN_ERROR 2 +#define SILKWORM_INVALID_HANDLE 3 +#define SILKWORM_INVALID_PATH 4 +#define SILKWORM_INVALID_SNAPSHOT 5 +#define SILKWORM_INVALID_MDBX_TXN 6 +#define SILKWORM_INVALID_BLOCK_RANGE 7 +#define SILKWORM_BLOCK_NOT_FOUND 8 +#define SILKWORM_UNKNOWN_CHAIN_ID 9 +#define SILKWORM_MDBX_ERROR 10 +#define SILKWORM_INVALID_BLOCK 11 +#define SILKWORM_DECODING_ERROR 12 + +typedef struct SilkwormHandle SilkwormHandle; + +SILKWORM_EXPORT int silkworm_init(SilkwormHandle** handle) SILKWORM_NOEXCEPT; + +struct SilkwormMemoryMappedFile { + const char* file_path; + const void* memory_address; + size_t memory_length; +}; + +struct SilkwormHeadersSnapshot { + SilkwormMemoryMappedFile segment; + SilkwormMemoryMappedFile header_hash_index; +}; + +struct SilkwormBodiesSnapshot { + SilkwormMemoryMappedFile segment; + SilkwormMemoryMappedFile block_num_index; }; -/** @brief Executes a batch of Ethereum blocks and writes resulting changes into the database. +struct SilkwormTransactionsSnapshot { + SilkwormMemoryMappedFile segment; + SilkwormMemoryMappedFile tx_hash_index; + SilkwormMemoryMappedFile tx_hash_2_block_index; +}; + +struct SilkwormChainSnapshot { + SilkwormHeadersSnapshot headers; + SilkwormBodiesSnapshot bodies; + SilkwormTransactionsSnapshot transactions; +}; + +SILKWORM_EXPORT int silkworm_add_snapshot(SilkwormHandle* handle, SilkwormChainSnapshot* snapshot) SILKWORM_NOEXCEPT; + +/** \brief Execute a batch of blocks and write resulting changes into the database. * - * @param[in] txn Valid read-write MDBX transaction. Must not be NULL. + * \param[in] handle Valid read-write MDBX transaction. Must not be zero. + * \param[in] txn Valid read-write MDBX transaction. Must not be zero. * This function does not commit nor abort the transaction. - * @param[in] chain_id EIP-155 chain ID. kSilkwormUnknownChainId is returned in case of an unknown or unsupported chain. - * @param[in] start_block The block height to start the execution from. - * @param[in] max_block Do not execute after this block. + * \param[in] chain_id EIP-155 chain ID. SILKWORM_UNKNOWN_CHAIN_ID is returned in case of an unknown or unsupported chain. + * \param[in] start_block The block height to start the execution from. + * \param[in] max_block Do not execute after this block. * max_block may be executed, or the execution may stop earlier if the batch is full. - * @param[in] batch_size The size of DB changes to accumulate before returning from this method. + * \param[in] batch_size The size of DB changes to accumulate before returning from this method. * Pass 0 if you want to execute just 1 block. - * @param[in] write_receipts Whether to write CBOR-encoded receipts into the DB. + * \param[in] write_receipts Whether to write CBOR-encoded receipts into the DB. * - * @param[out] last_executed_block The height of the last successfully executed block. + * \param[out] last_executed_block The height of the last successfully executed block. * Not written to if no blocks were executed, otherwise *last_executed_block ≤ max_block. - * @param[out] mdbx_error_code If an MDBX error occurs (this function returns kSilkwormMdbxError) + * \param[out] mdbx_error_code If an MDBX error occurs (this function returns kSilkwormMdbxError) * and mdbx_error_code isn't NULL, it's populated with the relevant MDBX error code. * - * @return A non-zero error value on failure and kSilkwormSuccess(=0) on success. - * kSilkwormBlockNotFound is probably OK: it simply means that the execution reached the end of the chain + * \return A non-zero error value on failure and SILKWORM_OK (=0) on success. + * SILKWORM_BLOCK_NOT_FOUND is probably OK: it simply means that the execution reached the end of the chain * (blocks up to and incl. last_executed_block were still executed). */ -SILKWORM_EXPORT -enum SilkwormStatusCode silkworm_execute_blocks( - MDBX_txn* txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block, - uint64_t batch_size, bool write_receipts, uint64_t* last_executed_block, - int* mdbx_error_code) SILKWORM_NOEXCEPT; +SILKWORM_EXPORT int silkworm_execute_blocks( + SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block, + uint64_t batch_size, bool write_receipts, uint64_t* last_executed_block, int* mdbx_error_code) SILKWORM_NOEXCEPT; + +SILKWORM_EXPORT int silkworm_fini(SilkwormHandle* handle) SILKWORM_NOEXCEPT; #if __cplusplus } diff --git a/silkworm/node/snapshot/repository.cpp b/silkworm/node/snapshot/repository.cpp index 66e8df7f76..badd821443 100644 --- a/silkworm/node/snapshot/repository.cpp +++ b/silkworm/node/snapshot/repository.cpp @@ -69,6 +69,16 @@ SnapshotRepository::~SnapshotRepository() { close(); } +void SnapshotRepository::add_snapshot_bundle(SnapshotBundle&& bundle) { + header_segments_[bundle.headers_snapshot_path.path()] = std::move(bundle.headers_snapshot); + body_segments_[bundle.bodies_snapshot_path.path()] = std::move(bundle.bodies_snapshot); + tx_segments_[bundle.tx_snapshot_path.path()] = std::move(bundle.tx_snapshot); + if (bundle.tx_snapshot_path.block_to() > segment_max_block_) { + segment_max_block_ = bundle.tx_snapshot_path.block_to() - 1; + } + idx_max_block_ = max_idx_available(); +} + void SnapshotRepository::reopen_folder() { SILK_INFO << "Reopen snapshot repository folder: " << settings_.repository_dir.string(); SnapshotPathList segment_files = get_segment_files(); diff --git a/silkworm/node/snapshot/repository.hpp b/silkworm/node/snapshot/repository.hpp index 75de4d0e95..6f70d47cc3 100644 --- a/silkworm/node/snapshot/repository.hpp +++ b/silkworm/node/snapshot/repository.hpp @@ -44,6 +44,15 @@ using HeaderSnapshotWalker = SnapshotWalker; using BodySnapshotWalker = SnapshotWalker; using TransactionSnapshotWalker = SnapshotWalker; +struct SnapshotBundle { + SnapshotPath headers_snapshot_path; + std::unique_ptr headers_snapshot; + SnapshotPath bodies_snapshot_path; + std::unique_ptr bodies_snapshot; + SnapshotPath tx_snapshot_path; + std::unique_ptr tx_snapshot; +}; + //! Read-only repository for all snapshot files. //! @details Some simplifications are currently in place: //! - it opens snapshots only on startup and they are immutable @@ -64,6 +73,8 @@ class SnapshotRepository { return get_files(kSegmentExtension); } + void add_snapshot_bundle(SnapshotBundle&& bundle); + void reopen_list(const SnapshotPathList& segment_files, bool optimistic = false); void reopen_file(const SnapshotPath& segment_path, bool optimistic = false); void reopen_folder();