aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core/blockchain.cpp
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-01-21 17:18:50 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-02-12 12:15:54 +0000
commitebc60a098d40506fdd0c5974a8644728d502e024 (patch)
treeb1e4cc9de425686a8b15a0a1ef993aa593384ae9 /src/cryptonote_core/blockchain.cpp
parentMerge pull request #4716 (diff)
downloadmonero-ebc60a098d40506fdd0c5974a8644728d502e024.tar.xz
ArticMine's new block weight algorithm
This curbs runaway growth while still allowing substantial spikes in block weight Original specification from ArticMine: here is the scaling proposal Define: LongTermBlockWeight Before fork: LongTermBlockWeight = BlockWeight At or after fork: LongTermBlockWeight = min(BlockWeight, 1.4*LongTermEffectiveMedianBlockWeight) Note: To avoid possible consensus issues over rounding the LongTermBlockWeight for a given block should be calculated to the nearest byte, and stored as a integer in the block itself. The stored LongTermBlockWeight is then used for future calculations of the LongTermEffectiveMedianBlockWeight and not recalculated each time. Define: LongTermEffectiveMedianBlockWeight LongTermEffectiveMedianBlockWeight = max(300000, MedianOverPrevious100000Blocks(LongTermBlockWeight)) Change Definition of EffectiveMedianBlockWeight From (current definition) EffectiveMedianBlockWeight = max(300000, MedianOverPrevious100Blocks(BlockWeight)) To (proposed definition) EffectiveMedianBlockWeight = min(max(300000, MedianOverPrevious100Blocks(BlockWeight)), 50*LongTermEffectiveMedianBlockWeight) Notes: 1) There are no other changes to the existing penalty formula, median calculation, fees etc. 2) There is the requirement to store the LongTermBlockWeight of a block unencrypted in the block itself. This is to avoid possible consensus issues over rounding and also to prevent the calculations from becoming unwieldy as we move away from the fork. 3) When the EffectiveMedianBlockWeight cap is reached it is still possible to mine blocks up to 2x the EffectiveMedianBlockWeight by paying the corresponding penalty.
Diffstat (limited to 'src/cryptonote_core/blockchain.cpp')
-rw-r--r--src/cryptonote_core/blockchain.cpp133
1 files changed, 121 insertions, 12 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index fa23b6bd2..9c6153212 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -167,6 +167,8 @@ static const struct {
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
+ m_long_term_block_weights(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
+ m_long_term_block_weights_height(0),
m_difficulty_for_next_block_top_hash(crypto::null_hash),
m_difficulty_for_next_block(1),
m_btc_valid(false)
@@ -492,6 +494,17 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id());
}
+ if (test_options && test_options->long_term_block_weight_window)
+ m_long_term_block_weights.set_capacity(test_options->long_term_block_weight_window);
+
+ // fill up the long term block weights to reach the required amount
+ const uint64_t db_height = m_db->height();
+ const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights.capacity(), db_height);
+ while (m_long_term_block_weights.size() < nblocks)
+ {
+ m_long_term_block_weights.push_front(db_height - 1 - m_long_term_block_weights.size());
+ }
+
update_next_cumulative_weight_limit();
return true;
}
@@ -606,6 +619,8 @@ block Blockchain::pop_block_from_blockchain()
throw;
}
+ pop_from_long_term_block_weights();
+
// return transactions from popped block to the tx_pool
for (transaction& tx : popped_txs)
{
@@ -655,6 +670,8 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
m_timestamps_and_difficulties_height = 0;
m_alternative_chains.clear();
invalidate_block_template_cache();
+ m_long_term_block_weights.clear();
+ m_long_term_block_weights_height = 0;
m_db->reset();
m_hardfork->init();
@@ -2947,7 +2964,8 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const
uint64_t needed_fee;
if (version >= HF_VERSION_PER_BYTE_FEE)
{
- uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, median, version);
+ const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
+ uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_block_weights.back() : median, version);
MDEBUG("Using " << print_money(fee_per_byte) << "/byte fee");
needed_fee = tx_weight * fee_per_byte;
// quantize fee up to 8 decimals
@@ -3010,7 +3028,8 @@ uint64_t Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const
base_reward = BLOCK_REWARD_OVERESTIMATE;
}
- uint64_t fee = get_dynamic_base_fee(base_reward, median, version);
+ const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
+ uint64_t fee = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_block_weights.back() : median, version);
const bool per_byte = version < HF_VERSION_PER_BYTE_FEE;
MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/" << (per_byte ? "byte" : "kB"));
return fee;
@@ -3507,7 +3526,8 @@ leave:
{
try
{
- new_height = m_db->add_block(bl, block_weight, cumulative_difficulty, already_generated_coins, txs);
+ uint64_t long_term_block_weight = get_next_long_term_block_weight(block_weight);
+ new_height = m_db->add_block(bl, block_weight, long_term_block_weight, cumulative_difficulty, already_generated_coins, txs);
}
catch (const KEY_IMAGE_EXISTS& e)
{
@@ -3560,20 +3580,109 @@ leave:
return true;
}
//------------------------------------------------------------------
-bool Blockchain::update_next_cumulative_weight_limit()
+void Blockchain::pop_from_long_term_block_weights()
+{
+ m_long_term_block_weights.pop_back();
+ --m_long_term_block_weights_height;
+ if (m_long_term_block_weights_height + 1 > m_long_term_block_weights.capacity())
+ {
+ uint64_t block_height = m_long_term_block_weights_height - m_long_term_block_weights.capacity() + 1;
+ m_long_term_block_weights.push_front(block_height);
+ }
+}
+//------------------------------------------------------------------
+uint64_t Blockchain::get_next_long_term_block_weight(uint64_t block_weight) const
{
- uint64_t full_reward_zone = get_min_block_weight(get_current_hard_fork_version());
+ PERF_TIMER(get_next_long_term_block_weight);
+
+ const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights.capacity(), m_db->height());
+ CHECK_AND_ASSERT_MES(m_long_term_block_weights.size() == nblocks, 0,
+ "m_long_term_block_weights is not the expected size");
+
+ const uint8_t hf_version = get_current_hard_fork_version();
+ if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
+ return block_weight;
+
+ std::vector<uint64_t> weights(m_long_term_block_weights.begin(), m_long_term_block_weights.end());
+ uint64_t long_term_median = epee::misc_utils::median(weights);
+ uint64_t long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
+
+ uint64_t short_term_constraint = long_term_effective_median_block_weight + long_term_effective_median_block_weight * 2 / 5;
+ uint64_t long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
+
+ return long_term_block_weight;
+}
+//------------------------------------------------------------------
+bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effective_median_block_weight)
+{
+ PERF_TIMER(update_next_cumulative_weight_limit);
LOG_PRINT_L3("Blockchain::" << __func__);
- std::vector<size_t> weights;
- get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
- uint64_t median = epee::misc_utils::median(weights);
- m_current_block_cumul_weight_median = median;
- if(median <= full_reward_zone)
- median = full_reward_zone;
+ uint64_t local_long_term_effective_median_block_weight;
+ if (!long_term_effective_median_block_weight)
+ long_term_effective_median_block_weight = &local_long_term_effective_median_block_weight;
+
+ // when we reach this, the last hf version is not yet written to the db
+ const uint64_t db_height = m_db->height();
+ const uint8_t hf_version = (m_long_term_block_weights_height + 1 < m_db->height()) ? m_db->get_hard_fork_version(db_height - 1) : get_current_hard_fork_version();
+ uint64_t full_reward_zone = get_min_block_weight(hf_version);
+ uint64_t long_term_block_weight;
+
+ // recalc, or reorg ? pop the last one(s) and recompute
+ uint64_t pop = 0;
+ if (db_height && db_height <= m_long_term_block_weights_height)
+ {
+ pop = m_long_term_block_weights_height - db_height + 1;
+ while (pop--)
+ pop_from_long_term_block_weights();
+ }
+
+ if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
+ {
+ std::vector<size_t> weights;
+ get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
+ m_current_block_cumul_weight_median = epee::misc_utils::median(weights);
+ long_term_block_weight = weights.back();
+ }
+ else
+ {
+ const uint64_t block_weight = m_db->get_block_weight(db_height - 1);
+
+ std::vector<uint64_t> weights(m_long_term_block_weights.begin(), m_long_term_block_weights.end());
+ uint64_t long_term_median = epee::misc_utils::median(weights);
+ *long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
+
+ uint64_t short_term_constraint = *long_term_effective_median_block_weight + *long_term_effective_median_block_weight * 2 / 5;
+ long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
+
+ weights = std::vector<uint64_t>(m_long_term_block_weights.begin(), m_long_term_block_weights.end());
+ if (weights.empty())
+ weights.resize(1);
+ weights[0] = long_term_block_weight;
+ long_term_median = epee::misc_utils::median(weights);
+ *long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
+ short_term_constraint = *long_term_effective_median_block_weight + *long_term_effective_median_block_weight * 2 / 5;
+
+ weights.clear();
+ get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
+
+ uint64_t short_term_median = epee::misc_utils::median(weights);
+ uint64_t effective_median_block_weight = std::min<uint64_t>(std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, short_term_median), CRYPTONOTE_SHORT_TERM_BLOCK_WEIGHT_SURGE_FACTOR * *long_term_effective_median_block_weight);
+
+ m_current_block_cumul_weight_median = effective_median_block_weight;
+ }
+
+ m_long_term_block_weights.push_back(long_term_block_weight);
+ m_long_term_block_weights_height = db_height;
+ const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights.capacity(), db_height);
+ CHECK_AND_ASSERT_MES(m_long_term_block_weights.size() == nblocks, false, "Bad m_long_term_block_weights size");
+
+ if (m_current_block_cumul_weight_median <= full_reward_zone)
+ m_current_block_cumul_weight_median = full_reward_zone;
+
+ m_current_block_cumul_weight_limit = m_current_block_cumul_weight_median * 2;
- m_current_block_cumul_weight_limit = median*2;
return true;
}
//------------------------------------------------------------------