v8: per byte fee, pad bulletproofs, fixed 11 ring size

This commit is contained in:
moneromooo-monero 2018-07-18 22:24:53 +01:00
parent 869b3bf824
commit 5ffb2ff9b7
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
55 changed files with 1241 additions and 878 deletions

View file

@ -155,7 +155,7 @@ 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_sz_limit(0), m_current_block_cumul_sz_median(0),
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_difficulty_for_next_block_top_hash(crypto::null_hash),
m_difficulty_for_next_block(1),
@ -482,7 +482,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id());
}
update_next_cumulative_size_limit();
update_next_cumulative_weight_limit();
return true;
}
//------------------------------------------------------------------
@ -631,7 +631,7 @@ block Blockchain::pop_block_from_blockchain()
m_blocks_txs_check.clear();
m_check_txin_table.clear();
update_next_cumulative_size_limit();
update_next_cumulative_weight_limit();
m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id());
invalidate_block_template_cache();
@ -650,7 +650,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
block_verification_context bvc = boost::value_initialized<block_verification_context>();
add_new_block(b, bvc);
update_next_cumulative_size_limit();
update_next_cumulative_weight_limit();
return bvc.m_added_to_main_chain && !bvc.m_verifivation_failed;
}
//------------------------------------------------------------------
@ -1113,7 +1113,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height)
}
//------------------------------------------------------------------
// This function validates the miner transaction reward
bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version)
bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version)
{
LOG_PRINT_L3("Blockchain::" << __func__);
//validate reward
@ -1131,11 +1131,11 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
}
}
std::vector<size_t> last_blocks_sizes;
get_last_n_blocks_sizes(last_blocks_sizes, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
if (!get_block_reward(epee::misc_utils::median(last_blocks_sizes), cumulative_block_size, already_generated_coins, base_reward, version))
std::vector<size_t> last_blocks_weights;
get_last_n_blocks_weights(last_blocks_weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
if (!get_block_reward(epee::misc_utils::median(last_blocks_weights), cumulative_block_weight, already_generated_coins, base_reward, version))
{
MERROR_VER("block size " << cumulative_block_size << " is bigger than allowed for this blockchain");
MERROR_VER("block weight " << cumulative_block_weight << " is bigger than allowed for this blockchain");
return false;
}
if(base_reward + fee < money_in_use)
@ -1165,8 +1165,8 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
return true;
}
//------------------------------------------------------------------
// get the block sizes of the last <count> blocks, and return by reference <sz>.
void Blockchain::get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count) const
// get the block weights of the last <count> blocks, and return by reference <sz>.
void Blockchain::get_last_n_blocks_weights(std::vector<size_t>& weights, size_t count) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@ -1177,26 +1177,26 @@ void Blockchain::get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count)
return;
m_db->block_txn_start(true);
// add size of last <count> blocks to vector <sz> (or less, if blockchain size < count)
// add weight of last <count> blocks to vector <weights> (or less, if blockchain size < count)
size_t start_offset = h - std::min<size_t>(h, count);
sz.reserve(sz.size() + h - start_offset);
weights.reserve(weights.size() + h - start_offset);
for(size_t i = start_offset; i < h; i++)
{
sz.push_back(m_db->get_block_size(i));
weights.push_back(m_db->get_block_weight(i));
}
m_db->block_txn_stop();
}
//------------------------------------------------------------------
uint64_t Blockchain::get_current_cumulative_blocksize_limit() const
uint64_t Blockchain::get_current_cumulative_block_weight_limit() const
{
LOG_PRINT_L3("Blockchain::" << __func__);
return m_current_block_cumul_sz_limit;
return m_current_block_cumul_weight_limit;
}
//------------------------------------------------------------------
uint64_t Blockchain::get_current_cumulative_blocksize_median() const
uint64_t Blockchain::get_current_cumulative_block_weight_median() const
{
LOG_PRINT_L3("Blockchain::" << __func__);
return m_current_block_cumul_sz_median;
return m_current_block_cumul_weight_median;
}
//------------------------------------------------------------------
//TODO: This function only needed minor modification to work with BlockchainDB,
@ -1213,7 +1213,7 @@ uint64_t Blockchain::get_current_cumulative_blocksize_median() const
bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
{
LOG_PRINT_L3("Blockchain::" << __func__);
size_t median_size;
size_t median_weight;
uint64_t already_generated_coins;
uint64_t pool_cookie;
@ -1250,20 +1250,20 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
diffic = get_difficulty_for_next_block();
CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead.");
median_size = m_current_block_cumul_sz_limit / 2;
median_weight = m_current_block_cumul_weight_limit / 2;
already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
CRITICAL_REGION_END();
size_t txs_size;
size_t txs_weight;
uint64_t fee;
if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee, expected_reward, m_hardfork->get_current_version()))
if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, m_hardfork->get_current_version()))
{
return false;
}
pool_cookie = m_tx_pool.cookie();
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
size_t real_txs_size = 0;
size_t real_txs_weight = 0;
uint64_t real_fee = 0;
CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock);
for(crypto::hash &cur_hash: b.tx_hashes)
@ -1275,11 +1275,11 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
continue;
}
tx_memory_pool::tx_details &cur_tx = cur_res->second;
real_txs_size += cur_tx.blob_size;
real_txs_weight += cur_tx.weight;
real_fee += cur_tx.fee;
if (cur_tx.blob_size != get_object_blobsize(cur_tx.tx))
if (cur_tx.weight != get_transaction_weight(cur_tx.tx))
{
LOG_ERROR("Creating block template: error: invalid transaction size");
LOG_ERROR("Creating block template: error: invalid transaction weight");
}
if (cur_tx.tx.version == 1)
{
@ -1301,9 +1301,9 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
}
}
}
if (txs_size != real_txs_size)
if (txs_weight != real_txs_weight)
{
LOG_ERROR("Creating block template: error: wrongly calculated transaction size");
LOG_ERROR("Creating block template: error: wrongly calculated transaction weight");
}
if (fee != real_fee)
{
@ -1311,70 +1311,70 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
}
CRITICAL_REGION_END();
MDEBUG("Creating block template: height " << height <<
", median size " << median_size <<
", median weight " << median_weight <<
", already generated coins " << already_generated_coins <<
", transaction size " << txs_size <<
", transaction weight " << txs_weight <<
", fee " << fee);
#endif
/*
two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know
block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size
two-phase miner transaction generation: we don't know exact block weight until we prepare block, but we don't know reward until we know
block weight, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block weight
*/
//make blocks coin-base tx looks close to real coinbase tx to get truthful blob size
//make blocks coin-base tx looks close to real coinbase tx to get truthful blob weight
uint8_t hf_version = m_hardfork->get_current_version();
size_t max_outs = hf_version >= 4 ? 1 : 11;
bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance");
size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx);
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
MDEBUG("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) <<
", cumulative size " << cumulative_size);
MDEBUG("Creating block template: miner tx weight " << get_transaction_weight(b.miner_tx) <<
", cumulative weight " << cumulative_weight);
#endif
for (size_t try_count = 0; try_count != 10; ++try_count)
{
r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance");
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
if (coinbase_blob_size > cumulative_size - txs_size)
size_t coinbase_weight = get_transaction_weight(b.miner_tx);
if (coinbase_weight > cumulative_weight - txs_weight)
{
cumulative_size = txs_size + coinbase_blob_size;
cumulative_weight = txs_weight + coinbase_weight;
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
MDEBUG("Creating block template: miner tx size " << coinbase_blob_size <<
", cumulative size " << cumulative_size << " is greater than before");
MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
", cumulative weight " << cumulative_weight << " is greater than before");
#endif
continue;
}
if (coinbase_blob_size < cumulative_size - txs_size)
if (coinbase_weight < cumulative_weight - txs_weight)
{
size_t delta = cumulative_size - txs_size - coinbase_blob_size;
size_t delta = cumulative_weight - txs_weight - coinbase_weight;
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
MDEBUG("Creating block template: miner tx size " << coinbase_blob_size <<
", cumulative size " << txs_size + coinbase_blob_size <<
MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
", cumulative weight " << txs_weight + coinbase_weight <<
" is less than before, adding " << delta << " zero bytes");
#endif
b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
//here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx))
if (cumulative_weight != txs_weight + get_transaction_weight(b.miner_tx))
{
CHECK_AND_ASSERT_MES(cumulative_size + 1 == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx));
CHECK_AND_ASSERT_MES(cumulative_weight + 1 == txs_weight + get_transaction_weight(b.miner_tx), false, "unexpected case: cumulative_weight=" << cumulative_weight << " + 1 is not equal txs_cumulative_weight=" << txs_weight << " + get_transaction_weight(b.miner_tx)=" << get_transaction_weight(b.miner_tx));
b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1);
if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx))
if (cumulative_weight != txs_weight + get_transaction_weight(b.miner_tx))
{
//fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size
//fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_weight
MDEBUG("Miner tx creation has no luck with delta_extra size = " << delta << " and " << delta - 1);
cumulative_size += delta - 1;
cumulative_weight += delta - 1;
continue;
}
MDEBUG("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count);
}
}
CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx));
CHECK_AND_ASSERT_MES(cumulative_weight == txs_weight + get_transaction_weight(b.miner_tx), false, "unexpected case: cumulative_weight=" << cumulative_weight << " is not equal txs_cumulative_weight=" << txs_weight << " + get_transaction_weight(b.miner_tx)=" << get_transaction_weight(b.miner_tx));
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
MDEBUG("Creating block template: miner tx size " << coinbase_blob_size <<
", cumulative size " << cumulative_size << " is now good");
MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
", cumulative weight " << cumulative_weight << " is now good");
#endif
cache_block_template(b, miner_address, ex_nonce, diffic, expected_reward, pool_cookie);
@ -2540,7 +2540,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh
if(m_show_time_stats)
{
size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx));
MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx) << " W: " << get_transaction_weight(tx));
}
if (!res)
return false;
@ -2597,12 +2597,27 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
// from v8, allow bulletproofs
if (hf_version < 8) {
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
if (bulletproof || !tx.rct_signatures.p.bulletproofs.empty())
{
MERROR("Bulletproofs are not allowed before v8");
tvc.m_invalid_output = true;
return false;
if (tx.version >= 2) {
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
if (bulletproof || !tx.rct_signatures.p.bulletproofs.empty())
{
MERROR("Bulletproofs are not allowed before v8");
tvc.m_invalid_output = true;
return false;
}
}
}
// from v9, forbid borromean range proofs
if (hf_version > 8) {
if (tx.version >= 2) {
const bool borromean = rct::is_rct_borromean(tx.rct_signatures.type);
if (borromean)
{
MERROR("Borromean range proofs are not allowed after v8");
tvc.m_invalid_output = true;
return false;
}
}
}
@ -2714,7 +2729,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
{
size_t n_unmixable = 0, n_mixable = 0;
size_t mixin = std::numeric_limits<size_t>::max();
const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_6 ? 6 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2;
const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_10 ? 10 : hf_version >= HF_VERSION_MIN_MIXIN_6 ? 6 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2;
for (const auto& txin : tx.vin)
{
// non txin_to_key inputs will be rejected below
@ -2743,6 +2758,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
if (hf_version >= HF_VERSION_MIN_MIXIN_10 && mixin != 10)
{
MERROR_VER("Tx " << get_transaction_hash(tx) << " has invalid ring size (" << (mixin + 1) << "), it should be 11");
tvc.m_low_mixin = true;
return false;
}
if (mixin < min_mixin)
{
if (n_unmixable == 0)
@ -3093,7 +3115,7 @@ void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const
}
//------------------------------------------------------------------
static uint64_t get_fee_quantization_mask()
uint64_t Blockchain::get_fee_quantization_mask()
{
static uint64_t mask = 0;
if (mask == 0)
@ -3106,16 +3128,27 @@ static uint64_t get_fee_quantization_mask()
}
//------------------------------------------------------------------
uint64_t Blockchain::get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size, uint8_t version)
uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version)
{
const uint64_t min_block_size = get_min_block_size(version);
const uint64_t fee_per_kb_base = version >= 5 ? DYNAMIC_FEE_PER_KB_BASE_FEE_V5 : DYNAMIC_FEE_PER_KB_BASE_FEE;
const uint64_t min_block_weight = get_min_block_weight(version);
if (median_block_weight < min_block_weight)
median_block_weight = min_block_weight;
uint64_t hi, lo;
if (median_block_size < min_block_size)
median_block_size = min_block_size;
if (version >= HF_VERSION_PER_BYTE_FEE)
{
lo = mul128(block_reward, DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT, &hi);
div128_32(hi, lo, min_block_weight, &hi, &lo);
div128_32(hi, lo, median_block_weight, &hi, &lo);
assert(hi == 0);
lo /= 5;
return lo;
}
uint64_t unscaled_fee_per_kb = (fee_per_kb_base * min_block_size / median_block_size);
uint64_t hi, lo = mul128(unscaled_fee_per_kb, block_reward, &hi);
const uint64_t fee_base = version >= 5 ? DYNAMIC_FEE_PER_KB_BASE_FEE_V5 : DYNAMIC_FEE_PER_KB_BASE_FEE;
uint64_t unscaled_fee_base = (fee_base * min_block_weight / median_block_weight);
lo = mul128(unscaled_fee_base, block_reward, &hi);
static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD % 1000000 == 0, "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD must be divisible by 1000000");
static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000 <= std::numeric_limits<uint32_t>::max(), "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD is too large");
@ -3133,29 +3166,48 @@ uint64_t Blockchain::get_dynamic_per_kb_fee(uint64_t block_reward, size_t median
}
//------------------------------------------------------------------
bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const
bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const
{
const uint8_t version = get_current_hard_fork_version();
uint64_t fee_per_kb;
if (version < HF_VERSION_DYNAMIC_FEE)
uint64_t median = 0;
uint64_t already_generated_coins = 0;
uint64_t base_reward = 0;
if (version >= HF_VERSION_DYNAMIC_FEE)
{
fee_per_kb = FEE_PER_KB;
median = m_current_block_cumul_weight_limit / 2;
already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
if (!get_block_reward(median, 1, already_generated_coins, base_reward, version))
return false;
}
uint64_t needed_fee;
if (version >= HF_VERSION_PER_BYTE_FEE)
{
uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, median, version);
MDEBUG("Using " << print_money(fee_per_byte) << "/byte fee");
needed_fee = tx_weight * fee_per_byte;
// quantize fee up to 8 decimals
const uint64_t mask = get_fee_quantization_mask();
needed_fee = (needed_fee + mask - 1) / mask * mask;
}
else
{
uint64_t median = m_current_block_cumul_sz_limit / 2;
uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
uint64_t base_reward;
if (!get_block_reward(median, 1, already_generated_coins, base_reward, version))
return false;
fee_per_kb = get_dynamic_per_kb_fee(base_reward, median, version);
}
MDEBUG("Using " << print_money(fee_per_kb) << "/kB fee");
uint64_t fee_per_kb;
if (version < HF_VERSION_DYNAMIC_FEE)
{
fee_per_kb = FEE_PER_KB;
}
else
{
fee_per_kb = get_dynamic_base_fee(base_reward, median, version);
}
MDEBUG("Using " << print_money(fee_per_kb) << "/kB fee");
uint64_t needed_fee = blob_size / 1024;
needed_fee += (blob_size % 1024) ? 1 : 0;
needed_fee *= fee_per_kb;
needed_fee = tx_weight / 1024;
needed_fee += (tx_weight % 1024) ? 1 : 0;
needed_fee *= fee_per_kb;
}
if (fee < needed_fee - needed_fee / 50) // keep a little 2% buffer on acceptance - no integer overflow
{
@ -3166,7 +3218,7 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const
}
//------------------------------------------------------------------
uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) const
uint64_t Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const
{
const uint8_t version = get_current_hard_fork_version();
@ -3176,16 +3228,16 @@ uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) cons
if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW)
grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1;
const uint64_t min_block_size = get_min_block_size(version);
std::vector<size_t> sz;
get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks);
sz.reserve(grace_blocks);
const uint64_t min_block_weight = get_min_block_weight(version);
std::vector<size_t> weights;
get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks);
weights.reserve(grace_blocks);
for (size_t i = 0; i < grace_blocks; ++i)
sz.push_back(min_block_size);
weights.push_back(min_block_weight);
uint64_t median = epee::misc_utils::median(sz);
if(median <= min_block_size)
median = min_block_size;
uint64_t median = epee::misc_utils::median(weights);
if(median <= min_block_weight)
median = min_block_weight;
uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
uint64_t base_reward;
@ -3195,8 +3247,9 @@ uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) cons
base_reward = BLOCK_REWARD_OVERESTIMATE;
}
uint64_t fee = get_dynamic_per_kb_fee(base_reward, median, version);
MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/kB");
uint64_t fee = get_dynamic_base_fee(base_reward, 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;
}
@ -3372,11 +3425,11 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
for (const auto &txid: txids)
{
cryptonote::transaction tx;
size_t blob_size;
size_t tx_weight;
uint64_t fee;
bool relayed, do_not_relay, double_spend_seen;
MINFO("Removing txid " << txid << " from the pool");
if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, blob_size, fee, relayed, do_not_relay, double_spend_seen))
if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, tx_weight, fee, relayed, do_not_relay, double_spend_seen))
{
MERROR("Failed to remove txid " << txid << " from the pool");
res = false;
@ -3536,8 +3589,8 @@ leave:
goto leave;
}
size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx);
size_t cumulative_block_size = coinbase_blob_size;
size_t coinbase_weight = get_transaction_weight(bl.miner_tx);
size_t cumulative_block_weight = coinbase_weight;
std::vector<transaction> txs;
key_images_container keys;
@ -3559,7 +3612,7 @@ leave:
for (const crypto::hash& tx_id : bl.tx_hashes)
{
transaction tx;
size_t blob_size = 0;
size_t tx_weight = 0;
uint64_t fee = 0;
bool relayed = false, do_not_relay = false, double_spend_seen = false;
TIME_MEASURE_START(aa);
@ -3578,7 +3631,7 @@ leave:
TIME_MEASURE_START(bb);
// get transaction with hash <tx_id> from tx_pool
if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee, relayed, do_not_relay, double_spend_seen))
if(!m_tx_pool.take_tx(tx_id, tx, tx_weight, fee, relayed, do_not_relay, double_spend_seen))
{
MERROR_VER("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
bvc.m_verifivation_failed = true;
@ -3649,7 +3702,7 @@ leave:
TIME_MEASURE_FINISH(cc);
t_checktx += cc;
fee_summary += fee;
cumulative_block_size += blob_size;
cumulative_block_weight += tx_weight;
}
m_blocks_txs_check.clear();
@ -3657,7 +3710,7 @@ leave:
TIME_MEASURE_START(vmt);
uint64_t base_reward = 0;
uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
if(!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins, bvc.m_partial_block_reward, m_hardfork->get_current_version()))
if(!validate_miner_transaction(bl, cumulative_block_weight, fee_summary, base_reward, already_generated_coins, bvc.m_partial_block_reward, m_hardfork->get_current_version()))
{
MERROR_VER("Block with id: " << id << " has incorrect miner transaction");
bvc.m_verifivation_failed = true;
@ -3666,11 +3719,11 @@ leave:
}
TIME_MEASURE_FINISH(vmt);
size_t block_size;
size_t block_weight;
difficulty_type cumulative_difficulty;
// populate various metadata about the block to be stored alongside it.
block_size = cumulative_block_size;
block_weight = cumulative_block_weight;
cumulative_difficulty = current_diffic;
// In the "tail" state when the minimum subsidy (implemented in get_block_reward) is in effect, the number of
// coins will eventually exceed MONEY_SUPPLY and overflow a uint64. To prevent overflow, cap already_generated_coins
@ -3691,7 +3744,7 @@ leave:
{
try
{
new_height = m_db->add_block(bl, block_size, cumulative_difficulty, already_generated_coins, txs);
new_height = m_db->add_block(bl, block_weight, cumulative_difficulty, already_generated_coins, txs);
}
catch (const KEY_IMAGE_EXISTS& e)
{
@ -3716,14 +3769,14 @@ leave:
TIME_MEASURE_FINISH(addblock);
// do this after updating the hard fork state since the size limit may change due to fork
update_next_cumulative_size_limit();
// do this after updating the hard fork state since the weight limit may change due to fork
update_next_cumulative_weight_limit();
MINFO("+++++ BLOCK SUCCESSFULLY ADDED" << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "HEIGHT " << new_height-1 << ", difficulty:\t" << current_diffic << std::endl << "block reward: " << print_money(fee_summary + base_reward) << "(" << print_money(base_reward) << " + " << print_money(fee_summary) << "), coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", " << block_processing_time << "(" << target_calculating_time << "/" << longhash_calculating_time << ")ms");
MINFO("+++++ BLOCK SUCCESSFULLY ADDED" << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "HEIGHT " << new_height-1 << ", difficulty:\t" << current_diffic << std::endl << "block reward: " << print_money(fee_summary + base_reward) << "(" << print_money(base_reward) << " + " << print_money(fee_summary) << "), coinbase_weight: " << coinbase_weight << ", cumulative weight: " << cumulative_block_weight << ", " << block_processing_time << "(" << target_calculating_time << "/" << longhash_calculating_time << ")ms");
if(m_show_time_stats)
{
MINFO("Height: " << new_height << " blob: " << coinbase_blob_size << " cumm: "
<< cumulative_block_size << " p/t: " << block_processing_time << " ("
MINFO("Height: " << new_height << " coinbase weight: " << coinbase_weight << " cumm: "
<< cumulative_block_weight << " p/t: " << block_processing_time << " ("
<< target_calculating_time << "/" << longhash_calculating_time << "/"
<< t1 << "/" << t2 << "/" << t3 << "/" << t_exists << "/" << t_pool
<< "/" << t_checktx << "/" << t_dblspnd << "/" << vmt << "/" << addblock << ")ms");
@ -3740,20 +3793,20 @@ leave:
return true;
}
//------------------------------------------------------------------
bool Blockchain::update_next_cumulative_size_limit()
bool Blockchain::update_next_cumulative_weight_limit()
{
uint64_t full_reward_zone = get_min_block_size(get_current_hard_fork_version());
uint64_t full_reward_zone = get_min_block_weight(get_current_hard_fork_version());
LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<size_t> sz;
get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
std::vector<size_t> weights;
get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
uint64_t median = epee::misc_utils::median(sz);
m_current_block_cumul_sz_median = median;
uint64_t median = epee::misc_utils::median(weights);
m_current_block_cumul_weight_median = median;
if(median <= full_reward_zone)
median = full_reward_zone;
m_current_block_cumul_sz_limit = median*2;
m_current_block_cumul_weight_limit = median*2;
return true;
}
//------------------------------------------------------------------
@ -4650,14 +4703,14 @@ void Blockchain::load_compiled_in_block_hashes()
std::vector<transaction> txs;
m_tx_pool.get_transactions(txs);
size_t blob_size;
size_t tx_weight;
uint64_t fee;
bool relayed, do_not_relay, double_spend_seen;
transaction pool_tx;
for(const transaction &tx : txs)
{
crypto::hash tx_hash = get_transaction_hash(tx);
m_tx_pool.take_tx(tx_hash, pool_tx, blob_size, fee, relayed, do_not_relay, double_spend_seen);
m_tx_pool.take_tx(tx_hash, pool_tx, tx_weight, fee, relayed, do_not_relay, double_spend_seen);
}
}
}