From 17b1f421c0b5d98954c5a6721034c7d55c6814ff Mon Sep 17 00:00:00 2001 From: j-berman Date: Mon, 27 May 2024 14:54:35 -0700 Subject: [PATCH] cleaner lmdb test structure for curve trees --- tests/unit_tests/blockchain_db.cpp | 82 ------------------------- tests/unit_tests/curve_trees.cpp | 95 +++++++++++++++++++++-------- tests/unit_tests/curve_trees.h | 16 ++--- tests/unit_tests/unit_tests_utils.h | 55 +++++++++++++++++ 4 files changed, 131 insertions(+), 117 deletions(-) diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp index bee4659b6..66219322e 100644 --- a/tests/unit_tests/blockchain_db.cpp +++ b/tests/unit_tests/blockchain_db.cpp @@ -39,7 +39,6 @@ #include "blockchain_db/blockchain_db.h" #include "blockchain_db/lmdb/db_lmdb.h" #include "cryptonote_basic/cryptonote_format_utils.h" -#include "curve_trees.h" using namespace cryptonote; using epee::string_tools::pod_to_hex; @@ -342,85 +341,4 @@ TYPED_TEST(BlockchainDBTest, RetrieveBlockData) ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1].first), hashes[1]); } -// TODO: implement this in curve_trees.cpp, consider removing CurveTreesUnitTest class -TYPED_TEST(BlockchainDBTest, GrowCurveTrees) -{ - Helios helios; - Selene selene; - - auto curve_trees = CurveTreesV1( - helios, - selene, - HELIOS_CHUNK_WIDTH, - SELENE_CHUNK_WIDTH); - - // Number of leaves for which x number of layers is required - const std::size_t NEED_1_LAYER = SELENE_CHUNK_WIDTH; - const std::size_t NEED_2_LAYERS = NEED_1_LAYER * HELIOS_CHUNK_WIDTH; - const std::size_t NEED_3_LAYERS = NEED_2_LAYERS * SELENE_CHUNK_WIDTH; - - const std::vector N_LEAVES{ - // Basic tests - 1, - 2, - - // Test with number of leaves {-1,0,+1} relative to chunk width boundaries - NEED_1_LAYER-1, - NEED_1_LAYER, - NEED_1_LAYER+1, - - NEED_2_LAYERS-1, - NEED_2_LAYERS, - NEED_2_LAYERS+1, - - NEED_3_LAYERS, - }; - - for (const std::size_t init_leaves : N_LEAVES) - { - for (const std::size_t ext_leaves : N_LEAVES) - { - // Only test 3rd layer once because it's a huge test - if (init_leaves > 1 && ext_leaves == NEED_3_LAYERS) - continue; - if (ext_leaves > 1 && init_leaves == NEED_3_LAYERS) - continue; - - boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - std::string dirPath = tempPath.string(); - - this->set_prefix(dirPath); - - ASSERT_NO_THROW(this->m_db->open(dirPath)); - - this->get_filenames(); - auto hardfork = HardFork(*this->m_db, 1, 0); - this->m_db->set_hard_fork(&hardfork); - - { - db_wtxn_guard guard(this->m_db); - - LOG_PRINT_L0("Adding " << init_leaves << " leaves to tree, then extending by " << ext_leaves << " leaves"); - - ASSERT_NO_THROW(this->m_db->grow_tree(curve_trees, generate_random_leaves(curve_trees, init_leaves))); - ASSERT_TRUE(this->m_db->audit_tree(curve_trees)); - - MDEBUG("Successfully added initial " << init_leaves << " leaves to tree, extending tree by " - << ext_leaves << " leaves"); - - ASSERT_NO_THROW(this->m_db->grow_tree(curve_trees, generate_random_leaves(curve_trees, ext_leaves))); - ASSERT_TRUE(this->m_db->audit_tree(curve_trees)); - - MDEBUG("Successfully extended by " << ext_leaves << " leaves"); - } - - ASSERT_NO_THROW(this->m_db->close()); - this->remove_files(); - this->m_db = new BlockchainLMDB(); - // WARNING: this->m_hardfork is now referencing a freed m_db - // TODO: make a cleaner test in curve_trees.cpp - } - } -} - } // anonymous namespace diff --git a/tests/unit_tests/curve_trees.cpp b/tests/unit_tests/curve_trees.cpp index 9092ed68d..b37895a12 100644 --- a/tests/unit_tests/curve_trees.cpp +++ b/tests/unit_tests/curve_trees.cpp @@ -28,7 +28,10 @@ #include "gtest/gtest.h" +#include "cryptonote_basic/cryptonote_format_utils.h" #include "curve_trees.h" +#include "misc_log_ex.h" +#include "unit_tests_utils.h" //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- @@ -579,6 +582,68 @@ static bool grow_tree(CurveTreesV1 &curve_trees, return curve_trees_accessor.validate_tree(tree_inout); } //---------------------------------------------------------------------------------------------------------------------- +static bool grow_tree_in_memory(const std::size_t init_leaves, + const std::size_t ext_leaves, + CurveTreesV1 &curve_trees, + CurveTreesUnitTest &curve_trees_accessor) +{ + LOG_PRINT_L1("Adding " << init_leaves << " leaves to tree, then extending by " << ext_leaves << " leaves"); + + CurveTreesUnitTest::Tree global_tree; + + // Initialize global tree with `init_leaves` + MDEBUG("Adding " << init_leaves << " leaves to tree"); + + bool res = grow_tree(curve_trees, + curve_trees_accessor, + init_leaves, + global_tree); + + CHECK_AND_ASSERT_MES(res, false, "failed to add inital leaves to tree in memory"); + + MDEBUG("Successfully added initial " << init_leaves << " leaves to tree in memory"); + + // Then extend the global tree by `ext_leaves` + MDEBUG("Extending tree by " << ext_leaves << " leaves"); + + res = grow_tree(curve_trees, + curve_trees_accessor, + ext_leaves, + global_tree); + + CHECK_AND_ASSERT_MES(res, false, "failed to extend tree in memory"); + + MDEBUG("Successfully extended by " << ext_leaves << " leaves in memory"); + return true; +} +//---------------------------------------------------------------------------------------------------------------------- +static bool grow_tree_db(const std::size_t init_leaves, + const std::size_t ext_leaves, + CurveTreesV1 &curve_trees, + unit_test::BlockchainLMDBTest &test_db) +{ + INIT_BLOCKCHAIN_LMDB_TEST_DB(); + + { + cryptonote::db_wtxn_guard guard(test_db.m_db); + + LOG_PRINT_L1("Adding " << init_leaves << " leaves to db, then extending by " << ext_leaves << " leaves"); + + test_db.m_db->grow_tree(curve_trees, generate_random_leaves(curve_trees, init_leaves)); + CHECK_AND_ASSERT_MES(test_db.m_db->audit_tree(curve_trees), false, "failed to add initial leaves to db"); + + MDEBUG("Successfully added initial " << init_leaves << " leaves to db, extending by " + << ext_leaves << " leaves"); + + test_db.m_db->grow_tree(curve_trees, generate_random_leaves(curve_trees, ext_leaves)); + CHECK_AND_ASSERT_MES(test_db.m_db->audit_tree(curve_trees), false, "failed to extend tree in db"); + + MDEBUG("Successfully extended tree in db by " << ext_leaves << " leaves"); + } + + return true; +} +//---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- // Test //---------------------------------------------------------------------------------------------------------------------- @@ -597,6 +662,7 @@ TEST(curve_trees, grow_tree) SELENE_CHUNK_WIDTH); CurveTreesUnitTest curve_trees_accessor{curve_trees}; + unit_test::BlockchainLMDBTest test_db; CHECK_AND_ASSERT_THROW_MES(HELIOS_CHUNK_WIDTH > 1, "helios width must be > 1"); CHECK_AND_ASSERT_THROW_MES(SELENE_CHUNK_WIDTH > 1, "selene width must be > 1"); @@ -633,33 +699,8 @@ TEST(curve_trees, grow_tree) if (ext_leaves > 1 && init_leaves == NEED_3_LAYERS) continue; - LOG_PRINT_L1("Adding " << init_leaves << " leaves to tree, then extending by " << ext_leaves << " leaves"); - - CurveTreesUnitTest::Tree global_tree; - - // Initialize global tree with `init_leaves` - MDEBUG("Adding " << init_leaves << " leaves to tree"); - - bool res = grow_tree(curve_trees, - curve_trees_accessor, - init_leaves, - global_tree); - - ASSERT_TRUE(res); - - MDEBUG("Successfully added initial " << init_leaves << " leaves to tree"); - - // Then extend the global tree by `ext_leaves` - MDEBUG("Extending tree by " << ext_leaves << " leaves"); - - res = grow_tree(curve_trees, - curve_trees_accessor, - ext_leaves, - global_tree); - - ASSERT_TRUE(res); - - MDEBUG("Successfully extended by " << ext_leaves << " leaves"); + ASSERT_TRUE(grow_tree_in_memory(init_leaves, ext_leaves, curve_trees, curve_trees_accessor)); + ASSERT_TRUE(grow_tree_db(init_leaves, ext_leaves, curve_trees, test_db)); } } } diff --git a/tests/unit_tests/curve_trees.h b/tests/unit_tests/curve_trees.h index a89032f18..6d838ec1d 100644 --- a/tests/unit_tests/curve_trees.h +++ b/tests/unit_tests/curve_trees.h @@ -30,12 +30,19 @@ #include "fcmp/curve_trees.h" #include "fcmp/tower_cycle.h" -#include "misc_log_ex.h" using Helios = fcmp::curve_trees::Helios; using Selene = fcmp::curve_trees::Selene; using CurveTreesV1 = fcmp::curve_trees::CurveTreesV1; +const std::vector generate_random_leaves(const CurveTreesV1 &curve_trees, + const std::size_t num_leaves); + +// https://github.com/kayabaNerve/fcmp-plus-plus/blob +// /b2742e86f3d18155fd34dd1ed69cb8f79b900fce/crypto/fcmps/src/tests.rs#L81-L82 +const std::size_t HELIOS_CHUNK_WIDTH = 38; +const std::size_t SELENE_CHUNK_WIDTH = 18; + // Helper class that can access the private members of the CurveTrees class class CurveTreesUnitTest { @@ -75,10 +82,3 @@ private: CurveTreesV1 &m_curve_trees; }; -const std::vector generate_random_leaves(const CurveTreesV1 &curve_trees, - const std::size_t num_leaves); - -// https://github.com/kayabaNerve/fcmp-plus-plus/blob -// /b2742e86f3d18155fd34dd1ed69cb8f79b900fce/crypto/fcmps/src/tests.rs#L81-L82 -const std::size_t HELIOS_CHUNK_WIDTH = 38; -const std::size_t SELENE_CHUNK_WIDTH = 18; diff --git a/tests/unit_tests/unit_tests_utils.h b/tests/unit_tests/unit_tests_utils.h index 65da7bf88..13a3c4b58 100644 --- a/tests/unit_tests/unit_tests_utils.h +++ b/tests/unit_tests/unit_tests_utils.h @@ -30,6 +30,12 @@ #pragma once +#include "gtest/gtest.h" + +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "misc_log_ex.h" + #include #include @@ -64,8 +70,57 @@ namespace unit_test private: std::atomic m_counter; }; + + class BlockchainLMDBTest + { + public: + BlockchainLMDBTest() : m_temp_db_dir(boost::filesystem::temp_directory_path().string() + "/monero-lmdb-tests/") + {} + + ~BlockchainLMDBTest() + { + delete m_db; + remove_files(); + } + + void init_new_db() + { + CHECK_AND_ASSERT_THROW_MES(this->m_db == nullptr, "expected nullptr m_db"); + this->m_db = new cryptonote::BlockchainLMDB(); + + const auto temp_db_path = boost::filesystem::unique_path(); + const std::string dir_path = m_temp_db_dir + temp_db_path.string(); + + MDEBUG("Creating test db at path " << dir_path); + ASSERT_NO_THROW(this->m_db->open(dir_path)); + } + + void init_hardfork(cryptonote::HardFork *hardfork) + { + hardfork->init(); + this->m_db->set_hard_fork(hardfork); + } + + void remove_files() + { + boost::filesystem::remove_all(m_temp_db_dir); + } + + cryptonote::BlockchainDB* m_db{nullptr}; + const std::string m_temp_db_dir; + }; } +#define INIT_BLOCKCHAIN_LMDB_TEST_DB() \ + test_db.init_new_db(); \ + auto hardfork = cryptonote::HardFork(*test_db.m_db, 1, 0); \ + test_db.init_hardfork(&hardfork); \ + auto scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \ + ASSERT_NO_THROW(test_db.m_db->close()); \ + delete test_db.m_db; \ + test_db.m_db = nullptr; \ + }) + # define ASSERT_EQ_MAP(val, map, key) \ do { \ auto found = map.find(key); \