Merge pull request #5124
b8787f43
ArticMine's new block weight algorithm (moneromooo-monero)
pull/200/head
commit
55305559c1
@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2014-2018, 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.
|
||||
|
||||
set(block_weight_sources
|
||||
block_weight.cpp)
|
||||
|
||||
set(block_weight_headers)
|
||||
|
||||
add_executable(block_weight
|
||||
${block_weight_sources}
|
||||
${block_weight_headers})
|
||||
target_link_libraries(block_weight
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
add_test(
|
||||
NAME block_weight
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/compare.py ${CMAKE_CURRENT_SOURCE_DIR}/block_weight.py ${CMAKE_CURRENT_BINARY_DIR}/block_weight)
|
@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#define IN_UNIT_TESTS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
|
||||
#define LONG_TERM_BLOCK_WEIGHT_WINDOW 5000
|
||||
|
||||
enum test_t
|
||||
{
|
||||
test_max = 0,
|
||||
test_lcg = 1,
|
||||
test_min = 2,
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class TestDB: public cryptonote::BaseTestDB
|
||||
{
|
||||
private:
|
||||
struct block_t
|
||||
{
|
||||
size_t weight;
|
||||
uint64_t long_term_weight;
|
||||
};
|
||||
|
||||
public:
|
||||
TestDB() { m_open = true; }
|
||||
|
||||
virtual void add_block( const cryptonote::block& blk
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const cryptonote::difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& blk_hash
|
||||
) override {
|
||||
blocks.push_back({block_weight, long_term_block_weight});
|
||||
}
|
||||
virtual uint64_t height() const override { return blocks.size(); }
|
||||
virtual size_t get_block_weight(const uint64_t &h) const override { return blocks[h].weight; }
|
||||
virtual uint64_t get_block_long_term_weight(const uint64_t &h) const override { return blocks[h].long_term_weight; }
|
||||
virtual crypto::hash top_block_hash() const override {
|
||||
uint64_t h = height();
|
||||
crypto::hash top = crypto::null_hash;
|
||||
if (h)
|
||||
*(uint64_t*)&top = h - 1;
|
||||
return top;
|
||||
}
|
||||
virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); }
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override { if (height >= hf.size()) hf.resize(height + 1); hf[height] = version; }
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const override { if (height >= hf.size()) return 255; return hf[height]; }
|
||||
|
||||
private:
|
||||
std::vector<block_t> blocks;
|
||||
std::vector<uint8_t> hf;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define PREFIX_WINDOW(hf_version,window) \
|
||||
std::unique_ptr<cryptonote::Blockchain> bc; \
|
||||
cryptonote::tx_memory_pool txpool(*bc); \
|
||||
bc.reset(new cryptonote::Blockchain(txpool)); \
|
||||
struct get_test_options { \
|
||||
const std::pair<uint8_t, uint64_t> hard_forks[3]; \
|
||||
const cryptonote::test_options test_options = { \
|
||||
hard_forks, \
|
||||
window, \
|
||||
}; \
|
||||
get_test_options(): hard_forks{std::make_pair(1, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)LONG_TERM_BLOCK_WEIGHT_WINDOW), std::make_pair((uint8_t)0, (uint64_t)0)} {} \
|
||||
} opts; \
|
||||
cryptonote::Blockchain *blockchain = bc.get(); \
|
||||
bool r = blockchain->init(new TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL); \
|
||||
if (!r) \
|
||||
{ \
|
||||
fprintf(stderr, "Failed to init blockchain\n"); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, LONG_TERM_BLOCK_WEIGHT_WINDOW)
|
||||
|
||||
static uint32_t lcg_seed = 0;
|
||||
|
||||
static uint32_t lcg()
|
||||
{
|
||||
lcg_seed = (lcg_seed * 0x100000001b3 + 0xcbf29ce484222325) & 0xffffffff;
|
||||
return lcg_seed;
|
||||
}
|
||||
|
||||
static void test(test_t t, uint64_t blocks)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 0; h < LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
cryptonote::block b;
|
||||
b.major_version = 1;
|
||||
b.minor_version = 1;
|
||||
bc->get_db().add_block(b, 300000, 300000, bc->get_db().height(), bc->get_db().height(), {});
|
||||
if (!bc->update_next_cumulative_weight_limit())
|
||||
{
|
||||
fprintf(stderr, "Failed to update cumulative weight limit 1\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint64_t h = 0; h < blocks; ++h)
|
||||
{
|
||||
uint64_t w;
|
||||
uint64_t effective_block_weight_median = bc->get_current_cumulative_block_weight_median();
|
||||
switch (t)
|
||||
{
|
||||
case test_lcg:
|
||||
{
|
||||
uint32_t r = lcg();
|
||||
int64_t wi = 90 + r % 500000 + 250000 + sin(h / 200.) * 350000;
|
||||
w = wi < 90 ? 90 : wi;
|
||||
break;
|
||||
}
|
||||
case test_max:
|
||||
w = bc->get_current_cumulative_block_weight_limit();
|
||||
break;
|
||||
case test_min:
|
||||
w = 90;
|
||||
break;
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
cryptonote::block b;
|
||||
b.major_version = 10;
|
||||
b.minor_version = 10;
|
||||
bc->get_db().add_block(std::move(b), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
|
||||
|
||||
if (!bc->update_next_cumulative_weight_limit())
|
||||
{
|
||||
fprintf(stderr, "Failed to update cumulative weight limit\n");
|
||||
exit(1);
|
||||
}
|
||||
std::cout << "H " << h << ", BW " << w << ", EMBW " << effective_block_weight_median << ", LTBW " << ltw << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test(test_max, 2 * LONG_TERM_BLOCK_WEIGHT_WINDOW);
|
||||
test(test_lcg, 9 * LONG_TERM_BLOCK_WEIGHT_WINDOW);
|
||||
test(test_min, 1 * LONG_TERM_BLOCK_WEIGHT_WINDOW);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
#!/usr/bin/python
|
||||
# Simulate a maximal block attack on the Monero network
|
||||
# This uses the scheme proposed by ArticMine
|
||||
# Written by Sarang Nother
|
||||
# Copyright (c) 2019 The Monero Project
|
||||
import sys
|
||||
import math
|
||||
|
||||
MEDIAN_WINDOW_SMALL = 100 # number of recent blocks for median computation
|
||||
MEDIAN_WINDOW_BIG = 5000
|
||||
MULTIPLIER_SMALL = 1.4 # multipliers for determining weights
|
||||
MULTIPLIER_BIG = 50.0
|
||||
MEDIAN_THRESHOLD = 300*1000 # initial value for median (scaled kB -> B)
|
||||
lcg_seed = 0
|
||||
embw = MEDIAN_THRESHOLD
|
||||
ltembw = MEDIAN_THRESHOLD
|
||||
|
||||
weights = [MEDIAN_THRESHOLD]*MEDIAN_WINDOW_SMALL # weights of recent blocks (B), with index -1 most recent
|
||||
lt_weights = [MEDIAN_THRESHOLD]*MEDIAN_WINDOW_BIG # long-term weights
|
||||
|
||||
# Compute the median of a list
|
||||
def get_median(vec):
|
||||
#temp = vec
|
||||
temp = sorted(vec)
|
||||
if len(temp) % 2 == 1:
|
||||
return temp[len(temp)/2]
|
||||
else:
|
||||
return int((temp[len(temp)/2]+temp[len(temp)/2-1])/2)
|
||||
|
||||
def LCG():
|
||||
global lcg_seed
|
||||
lcg_seed = (lcg_seed * 0x100000001b3 + 0xcbf29ce484222325) & 0xffffffff
|
||||
return lcg_seed
|
||||
|
||||
def run(t, blocks):
|
||||
global embw
|
||||
global ltembw
|
||||
|
||||
weights = [MEDIAN_THRESHOLD]*MEDIAN_WINDOW_SMALL # weights of recent blocks (B), with index -1 most recent
|
||||
lt_weights = [MEDIAN_THRESHOLD]*MEDIAN_WINDOW_BIG # long-term weights
|
||||
|
||||
for block in range(blocks):
|
||||
# determine the long-term effective weight
|
||||
ltmedian = get_median(lt_weights[-MEDIAN_WINDOW_BIG:])
|
||||
ltembw = max(MEDIAN_THRESHOLD,ltmedian)
|
||||
|
||||
# determine the effective weight
|
||||
stmedian = get_median(weights[-MEDIAN_WINDOW_SMALL:])
|
||||
embw = min(max(MEDIAN_THRESHOLD,stmedian),int(MULTIPLIER_BIG*ltembw))
|
||||
|
||||
# drop the lowest values
|
||||
weights = weights[1:]
|
||||
lt_weights = lt_weights[1:]
|
||||
|
||||
# add a block of max weight
|
||||
if t == 0:
|
||||
max_weight = 2 * embw
|
||||
elif t == 1:
|
||||
r = LCG()
|
||||
max_weight = int(90 + r % 500000 + 250000 + math.sin(block / 200.) * 350000)
|
||||
if max_weight < 90: max_weight = 90
|
||||
elif t == 2:
|
||||
max_weight = 90
|
||||
else:
|
||||
sys.exit(1)
|
||||
weights.append(max_weight)
|
||||
lt_weights.append(min(max_weight,int(ltembw + int(ltembw * 2 / 5))))
|
||||
|
||||
#print "H %u, r %u, BW %u, EMBW %u, LTBW %u, LTEMBW %u, ltmedian %u" % (block, r, max_weight, embw, lt_weights[-1], ltembw, ltmedian)
|
||||
print "H %u, BW %u, EMBW %u, LTBW %u" % (block, max_weight, embw, lt_weights[-1])
|
||||
|
||||
run(0, 2 * MEDIAN_WINDOW_BIG)
|
||||
run(1, 9 * MEDIAN_WINDOW_BIG)
|
||||
run(2, 1 * MEDIAN_WINDOW_BIG)
|
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
print 'running: ', sys.argv[1]
|
||||
S0 = subprocess.check_output(sys.argv[1], stderr=subprocess.STDOUT)
|
||||
print 'running: ', sys.argv[2]
|
||||
S1 = subprocess.check_output(sys.argv[2], stderr=subprocess.STDOUT)
|
||||
print 'comparing'
|
||||
if S0 != S1:
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
@ -0,0 +1,384 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#define IN_UNIT_TESTS
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
|
||||
#define TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW 5000
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class TestDB: public cryptonote::BaseTestDB
|
||||
{
|
||||
private:
|
||||
struct block_t
|
||||
{
|
||||
size_t weight;
|
||||
uint64_t long_term_weight;
|
||||
};
|
||||
|
||||
public:
|
||||
TestDB() { m_open = true; }
|
||||
|
||||
virtual void add_block( const cryptonote::block& blk
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const cryptonote::difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& blk_hash
|
||||
) override {
|
||||
blocks.push_back({block_weight, long_term_block_weight});
|
||||
}
|
||||
virtual uint64_t height() const override { return blocks.size(); }
|
||||
virtual size_t get_block_weight(const uint64_t &h) const override { return blocks[h].weight; }
|
||||
virtual uint64_t get_block_long_term_weight(const uint64_t &h) const override { return blocks[h].long_term_weight; }
|
||||
virtual crypto::hash top_block_hash() const override {
|
||||
uint64_t h = height();
|
||||
crypto::hash top = crypto::null_hash;
|
||||
if (h)
|
||||
*(uint64_t*)&top = h - 1;
|
||||
return top;
|
||||
}
|
||||
virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); }
|
||||
|
||||
private:
|
||||
std::vector<block_t> blocks;
|
||||
};
|
||||
|
||||
static uint32_t lcg_seed = 0;
|
||||
|
||||
static uint32_t lcg()
|
||||
{
|
||||
lcg_seed = (lcg_seed * 0x100000001b3 + 0xcbf29ce484222325) & 0xffffffff;
|
||||
return lcg_seed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define PREFIX_WINDOW(hf_version,window) \
|
||||
std::unique_ptr<cryptonote::Blockchain> bc; \
|
||||
cryptonote::tx_memory_pool txpool(*bc); \
|
||||
bc.reset(new cryptonote::Blockchain(txpool)); \
|
||||
struct get_test_options { \
|
||||
const std::pair<uint8_t, uint64_t> hard_forks[3]; \
|
||||
const cryptonote::test_options test_options = { \
|
||||
hard_forks, \
|
||||
window, \
|
||||
}; \
|
||||
get_test_options(): hard_forks{std::make_pair(1, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)1), std::make_pair((uint8_t)0, (uint64_t)0)} {} \
|
||||
} opts; \
|
||||
cryptonote::Blockchain *blockchain = bc.get(); \
|
||||
bool r = blockchain->init(new TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL); \
|
||||
ASSERT_TRUE(r)
|
||||
|
||||
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW)
|
||||
|
||||
TEST(long_term_block_weight, empty_short)
|
||||
{
|
||||
PREFIX(9);
|
||||
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
|
||||
ASSERT_EQ(bc->get_current_cumulative_block_weight_median(), CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5);
|
||||
ASSERT_EQ(bc->get_current_cumulative_block_weight_limit(), CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 * 2);
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, identical_before_fork)
|
||||
{
|
||||
PREFIX(9);
|
||||
|
||||
for (uint64_t h = 1; h < 10 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
size_t w = h < CRYPTONOTE_REWARD_BLOCKS_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
for (uint64_t h = 0; h < 10 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
ASSERT_EQ(bc->get_db().get_block_long_term_weight(h), bc->get_db().get_block_weight(h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, identical_after_fork_before_long_term_window)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 1; h <= TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
for (uint64_t h = 0; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
ASSERT_EQ(bc->get_db().get_block_long_term_weight(h), bc->get_db().get_block_weight(h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, ceiling_at_30000000)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 0; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW + TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 2 - 1; ++h)
|
||||
{
|
||||
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
ASSERT_EQ(bc->get_current_cumulative_block_weight_median(), 15000000);
|
||||
ASSERT_EQ(bc->get_current_cumulative_block_weight_limit(), 30000000);
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, multi_pop)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 1; h <= TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW + 20; ++h)
|
||||
{
|
||||
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
|
||||
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
|
||||
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
|
||||
|
||||
for (uint64_t h = 0; h < 4; ++h)
|
||||
{
|
||||
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
|
||||
cryptonote::block b;
|
||||
std::vector<cryptonote::transaction> txs;
|
||||
bc->get_db().pop_block(b, txs);
|
||||
bc->get_db().pop_block(b, txs);
|
||||
bc->get_db().pop_block(b, txs);
|
||||
bc->get_db().pop_block(b, txs);
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
|
||||
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
|
||||
ASSERT_EQ(effective_limit, bc->get_current_cumulative_block_weight_limit());
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, multiple_updates)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 1; h <= 3 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
|
||||
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
|
||||
ASSERT_EQ(effective_limit, bc->get_current_cumulative_block_weight_limit());
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
|
||||
ASSERT_EQ(effective_limit, bc->get_current_cumulative_block_weight_limit());
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
|
||||
ASSERT_EQ(effective_limit, bc->get_current_cumulative_block_weight_limit());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, pop_invariant_max)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 1; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW - 10; ++h)
|
||||
{
|
||||
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
|
||||
for (int n = 0; n < 1000; ++n)
|
||||
{
|
||||
// pop some blocks, then add some more
|
||||
int remove = 1 + (n * 17) % 8;
|
||||
int add = (n * 23) % 12;
|
||||
|
||||
// save long term block weights we're about to remove
|
||||
uint64_t old_ltbw[16], h0 = bc->get_db().height() - remove - 1;
|
||||
for (int i = -2; i < remove; ++i)
|
||||
{
|
||||
old_ltbw[i + 2] = bc->get_db().get_block_long_term_weight(h0 + i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < remove; ++i)
|
||||
{
|
||||
cryptonote::block b;
|
||||
std::vector<cryptonote::transaction> txs;
|
||||
bc->get_db().pop_block(b, txs);
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
for (int i = 0; i < add; ++i)
|
||||
{
|
||||
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
|
||||
// check the new values are the same as the old ones
|
||||
for (int i = -2; i < std::min(add, remove); ++i)
|
||||
{
|
||||
ASSERT_EQ(bc->get_db().get_block_long_term_weight(h0 + i), old_ltbw[i + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, pop_invariant_random)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
for (uint64_t h = 1; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW - 10; ++h)
|
||||
{
|
||||
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
}
|
||||
|
||||
for (int n = 0; n < 1000; ++n)
|
||||
{
|
||||
// pop some blocks, then add some more
|
||||
int remove = 1 + (n * 17) % 8;
|
||||
int add = (n * 23) % 123;
|
||||
|
||||
// save long term block weights we're about to remove
|
||||
uint64_t old_ltbw[16], h0 = bc->get_db().height() - remove - 1;
|
||||
for (int i = -2; i < remove; ++i)
|
||||
{
|
||||
old_ltbw[i + 2] = bc->get_db().get_block_long_term_weight(h0 + i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < remove; ++i)
|
||||
{
|
||||
cryptonote::block b;
|
||||
std::vector<cryptonote::transaction> txs;
|
||||
bc->get_db().pop_block(b, txs);
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
|
||||
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
|
||||
ASSERT_EQ(effective_limit, bc->get_current_cumulative_block_weight_limit());
|
||||
}
|
||||
for (int i = 0; i < add; ++i)
|
||||
{
|
||||
lcg_seed = bc->get_db().height();
|
||||
uint32_t r = lcg();
|
||||
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : (r % bc->get_current_cumulative_block_weight_limit());
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
|
||||
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
|
||||
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
|
||||
ASSERT_EQ(effective_limit, bc->get_current_cumulative_block_weight_limit());
|
||||
}
|
||||
|
||||
// check the new values are the same as the old ones
|
||||
for (int i = -2; i < std::min(add, remove); ++i)
|
||||
{
|
||||
ASSERT_EQ(bc->get_db().get_block_long_term_weight(h0 + i), old_ltbw[i + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(long_term_block_weight, long_growth_spike_and_drop)
|
||||
{
|
||||
PREFIX(10);
|
||||
|
||||
uint64_t long_term_effective_median_block_weight;
|
||||
|
||||
// constant init
|
||||
for (uint64_t h = 0; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
size_t w = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
|
||||
}
|
||||
ASSERT_EQ(long_term_effective_median_block_weight, 300000);
|
||||
|
||||
// slow 10% yearly for a year (scaled down by 100000 / TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW) -> 8% change
|
||||
for (uint64_t h = 0; h < 365 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000; ++h)
|
||||
{
|
||||
//size_t w = bc->get_current_cumulative_block_weight_median() * rate;
|
||||
float t = h / float(365 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000);
|
||||
size_t w = 300000 + t * 30000;
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
|
||||
}
|
||||
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
|
||||
ASSERT_LT(long_term_effective_median_block_weight, 300000 * 1.09);
|
||||
|
||||
// spike over three weeks - does not move much
|
||||
for (uint64_t h = 0; h < 21 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000; ++h)
|
||||
{
|
||||
size_t w = bc->get_current_cumulative_block_weight_limit();
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
|
||||
}
|
||||
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
|
||||
ASSERT_LT(long_term_effective_median_block_weight, 300000 * 1.09);
|
||||
|
||||
// drop - does not move much
|
||||
for (uint64_t h = 0; h < 21 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000; ++h)
|
||||
{
|
||||
size_t w = bc->get_current_cumulative_block_weight_median() * .25;
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {});
|
||||
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
|
||||
}
|
||||
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
|
||||
ASSERT_LT(long_term_effective_median_block_weight, 300000 * 1.09);
|
||||
}
|
Loading…
Reference in new issue