242 lines
12 KiB
C++
242 lines
12 KiB
C++
// Copyright (c) 2018-2024, The Monero Project
|
|
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
// permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
// conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
// of conditions and the following disclaimer in the documentation and/or other
|
|
// materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
// used to endorse or promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "misc_log_ex.h"
|
|
#include "cryptonote_config.h"
|
|
#include "common/pruning.h"
|
|
|
|
#define ASSERT_EX(x) do { bool ex = false; try { x; } catch(...) { ex = true; } ASSERT_TRUE(ex); } while(0)
|
|
|
|
TEST(pruning, parts)
|
|
{
|
|
ASSERT_EQ(tools::get_pruning_stripe(tools::make_pruning_seed(3, 2)), 3);
|
|
ASSERT_EQ(tools::get_pruning_stripe(tools::make_pruning_seed(1, 2)), 1);
|
|
ASSERT_EQ(tools::get_pruning_stripe(tools::make_pruning_seed(7, 7)), 7);
|
|
|
|
ASSERT_EQ(tools::get_pruning_log_stripes(tools::make_pruning_seed(1, 2)), 2);
|
|
ASSERT_EQ(tools::get_pruning_log_stripes(tools::make_pruning_seed(1, 0)), 0);
|
|
ASSERT_EQ(tools::get_pruning_log_stripes(tools::make_pruning_seed(1, 7)), 7);
|
|
ASSERT_EQ(tools::get_pruning_log_stripes(tools::make_pruning_seed(7, 7)), 7);
|
|
|
|
for (uint32_t log_stripes = 1; log_stripes <= tools::PRUNING_SEED_LOG_STRIPES_MASK; ++log_stripes)
|
|
{
|
|
for (uint32_t stripe = 1; stripe <= (1 << log_stripes); ++stripe)
|
|
{
|
|
ASSERT_EQ(tools::get_pruning_log_stripes(tools::make_pruning_seed(stripe, log_stripes)), log_stripes);
|
|
ASSERT_EQ(tools::get_pruning_stripe(tools::make_pruning_seed(stripe, log_stripes)), stripe);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(pruning, out_of_range)
|
|
{
|
|
ASSERT_EX(tools::make_pruning_seed(5, 2));
|
|
ASSERT_EX(tools::make_pruning_seed(0, 2));
|
|
}
|
|
|
|
TEST(pruning, fits)
|
|
{
|
|
const uint32_t log_stripes = 3;
|
|
const uint32_t num_stripes = 1 << log_stripes;
|
|
for (uint32_t stripe = 1; stripe <= num_stripes; ++stripe)
|
|
{
|
|
const uint32_t seed = tools::make_pruning_seed(stripe, log_stripes);
|
|
ASSERT_NE(seed, 0);
|
|
ASSERT_EQ(tools::get_pruning_log_stripes(seed), log_stripes);
|
|
ASSERT_EQ(tools::get_pruning_stripe(seed), stripe);
|
|
}
|
|
}
|
|
|
|
TEST(pruning, tip)
|
|
{
|
|
static constexpr uint64_t H = CRYPTONOTE_PRUNING_TIP_BLOCKS + 1000;
|
|
static_assert(H >= CRYPTONOTE_PRUNING_TIP_BLOCKS, "H must be >= CRYPTONOTE_PRUNING_TIP_BLOCKS");
|
|
for (uint64_t h = H - CRYPTONOTE_PRUNING_TIP_BLOCKS; h < H; ++h)
|
|
{
|
|
uint32_t pruning_seed = tools::get_pruning_seed(h, H, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
ASSERT_EQ(pruning_seed, 0);
|
|
for (pruning_seed = 0; pruning_seed <= (1 << CRYPTONOTE_PRUNING_LOG_STRIPES); ++pruning_seed)
|
|
ASSERT_TRUE(tools::has_unpruned_block(h, H, pruning_seed));
|
|
}
|
|
}
|
|
|
|
TEST(pruning, seed)
|
|
{
|
|
const uint64_t SS = CRYPTONOTE_PRUNING_STRIPE_SIZE;
|
|
const uint64_t NS = 1 << CRYPTONOTE_PRUNING_LOG_STRIPES;
|
|
const uint64_t TB = NS * SS;
|
|
|
|
for (uint64_t cycle = 0; cycle < 10; ++cycle)
|
|
{
|
|
const uint64_t O = TB * cycle;
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + 0, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 1);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + 1, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 1);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + SS-1, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 1);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + SS, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 2);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + SS*2-1, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 2);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + SS*2, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 3);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + SS*NS-1, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), NS);
|
|
ASSERT_EQ(tools::get_pruning_stripe(O + SS*NS, 10000000, CRYPTONOTE_PRUNING_LOG_STRIPES), 1);
|
|
}
|
|
}
|
|
|
|
TEST(pruning, match)
|
|
{
|
|
static constexpr uint64_t H = CRYPTONOTE_PRUNING_TIP_BLOCKS + 1000;
|
|
static_assert(H >= CRYPTONOTE_PRUNING_TIP_BLOCKS, "H must be >= CRYPTONOTE_PRUNING_TIP_BLOCKS");
|
|
for (uint64_t h = 0; h < H - CRYPTONOTE_PRUNING_TIP_BLOCKS; ++h)
|
|
{
|
|
uint32_t pruning_seed = tools::get_pruning_seed(h, H, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
uint32_t pruning_stripe = tools::get_pruning_stripe(pruning_seed);
|
|
ASSERT_TRUE(pruning_stripe > 0 && pruning_stripe <= (1 << CRYPTONOTE_PRUNING_LOG_STRIPES));
|
|
for (uint32_t other_pruning_stripe = 1; other_pruning_stripe <= (1 << CRYPTONOTE_PRUNING_LOG_STRIPES); ++other_pruning_stripe)
|
|
{
|
|
uint32_t other_pruning_seed = tools::make_pruning_seed(other_pruning_stripe, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
ASSERT_TRUE(tools::has_unpruned_block(h, H, other_pruning_seed) == (other_pruning_seed == pruning_seed));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(pruning, stripe_size)
|
|
{
|
|
static constexpr uint64_t H = CRYPTONOTE_PRUNING_TIP_BLOCKS + CRYPTONOTE_PRUNING_STRIPE_SIZE * (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) + 1000;
|
|
static_assert(H >= CRYPTONOTE_PRUNING_TIP_BLOCKS + CRYPTONOTE_PRUNING_STRIPE_SIZE * (1 << CRYPTONOTE_PRUNING_LOG_STRIPES), "H must be >= that stuff in front");
|
|
for (uint32_t pruning_stripe = 1; pruning_stripe <= (1 << CRYPTONOTE_PRUNING_LOG_STRIPES); ++pruning_stripe)
|
|
{
|
|
uint32_t pruning_seed = tools::make_pruning_seed(pruning_stripe, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
unsigned int current_run = 0, best_run = 0;
|
|
for (uint64_t h = 0; h < H - CRYPTONOTE_PRUNING_TIP_BLOCKS; ++h)
|
|
{
|
|
if (tools::has_unpruned_block(h, H, pruning_seed))
|
|
{
|
|
++current_run;
|
|
}
|
|
else if (current_run)
|
|
{
|
|
ASSERT_EQ(current_run, CRYPTONOTE_PRUNING_STRIPE_SIZE);
|
|
best_run = std::max(best_run, current_run);
|
|
current_run = 0;
|
|
}
|
|
}
|
|
ASSERT_EQ(best_run, CRYPTONOTE_PRUNING_STRIPE_SIZE);
|
|
}
|
|
}
|
|
|
|
TEST(pruning, next_unpruned)
|
|
{
|
|
static_assert((1 << CRYPTONOTE_PRUNING_LOG_STRIPES) >= 4, "CRYPTONOTE_PRUNING_LOG_STRIPES too low");
|
|
|
|
const uint64_t SS = CRYPTONOTE_PRUNING_STRIPE_SIZE;
|
|
const uint64_t NS = 1 << CRYPTONOTE_PRUNING_LOG_STRIPES;
|
|
const uint64_t TB = NS * SS;
|
|
|
|
for (uint64_t h = 0; h < 100; ++h)
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(h, 10000000, 0), h);
|
|
|
|
const uint32_t seed1 = tools::make_pruning_seed(1, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seed2 = tools::make_pruning_seed(2, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seed3 = tools::make_pruning_seed(3, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seed4 = tools::make_pruning_seed(4, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seedNS = tools::make_pruning_seed(NS, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(0, 10000000, seed1), 0);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(1, 10000000, seed1), 1);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS-1, 10000000, seed1), SS-1);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS, 10000000, seed1), TB);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(TB, 10000000, seed1), TB);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(TB-1, 10000000, seed1), TB);
|
|
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(0, 10000000, seed2), SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(1, 10000000, seed2), SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS-1, 10000000, seed2), SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS, 10000000, seed2), SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(2*SS-1, 10000000, seed2), 2*SS-1);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(2*SS, 10000000, seed2), TB+SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(TB+2*SS,10000000, seed2), TB*2+SS);
|
|
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(0, 10000000, seed3), SS*2);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS, 10000000, seed3), SS*2);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(2*SS, 10000000, seed3), SS*2);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(3*SS-1, 10000000, seed3), SS*3-1);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(3*SS, 10000000, seed3), TB+SS*2);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(TB+3*SS,10000000, seed3), TB*2+SS*2);
|
|
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS, 10000000, seed4), 3*SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(4*SS-1, 10000000, seed4), 4*SS-1);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(4*SS, 10000000, seed4), TB+3*SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(TB+4*SS,10000000, seed4), TB*2+3*SS);
|
|
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(SS, 10000000, seedNS), (NS-1)*SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(NS*SS-1,10000000, seedNS), NS*SS-1);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(NS*SS, 10000000, seedNS), TB+(NS-1)*SS);
|
|
ASSERT_EQ(tools::get_next_unpruned_block_height(TB+NS*SS, 10000000, seedNS), TB*2+(NS-1)*SS);
|
|
}
|
|
|
|
TEST(pruning, next_pruned)
|
|
{
|
|
static_assert((1 << CRYPTONOTE_PRUNING_LOG_STRIPES) >= 4, "CRYPTONOTE_PRUNING_LOG_STRIPES too low");
|
|
|
|
const uint64_t SS = CRYPTONOTE_PRUNING_STRIPE_SIZE;
|
|
const uint64_t NS = 1 << CRYPTONOTE_PRUNING_LOG_STRIPES;
|
|
const uint64_t TB = NS * SS;
|
|
|
|
const uint32_t seed1 = tools::make_pruning_seed(1, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seed2 = tools::make_pruning_seed(2, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seedNS_1 = tools::make_pruning_seed(NS-1, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
const uint32_t seedNS = tools::make_pruning_seed(NS, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
|
|
|
for (uint64_t h = 0; h < 100; ++h)
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(h, 10000000, 0), 10000000);
|
|
for (uint64_t h = 10000000 - 1 - CRYPTONOTE_PRUNING_TIP_BLOCKS; h < 10000000; ++h)
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(h, 10000000, 0), 10000000);
|
|
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(1, 10000000, seed1), SS);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS-1, 10000000, seed1), SS);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS, 10000000, seed1), SS);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(TB-1, 10000000, seed1), TB-1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(TB, 10000000, seed1), TB+SS);
|
|
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(1, 10000000, seed2), 1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS-1, 10000000, seed2), SS-1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS, 10000000, seed2), 2*SS);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(TB-1, 10000000, seed2), TB-1);
|
|
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(1, 10000000, seedNS_1), 1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS-1, 10000000, seedNS_1), SS-1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS, 10000000, seedNS_1), SS);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(TB-1, 10000000, seedNS_1), TB-1);
|
|
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(1, 10000000, seedNS), 1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS-1, 10000000, seedNS), SS-1);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(SS, 10000000, seedNS), SS);
|
|
ASSERT_EQ(tools::get_next_pruned_block_height(TB-1, 10000000, seedNS), TB);
|
|
}
|