aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core/blockchain.cpp
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-07-18 22:24:53 +0100
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-09-11 13:38:07 +0000
commit5ffb2ff9b7c301eda5811a939c705f26627c4735 (patch)
treeac1ed0c55f69db9e65ebca9567bf3013e55c3bb6 /src/cryptonote_core/blockchain.cpp
parentbulletproofs: a few fixes from the Kudelski review (diff)
downloadmonero-5ffb2ff9b7c301eda5811a939c705f26627c4735.tar.xz
v8: per byte fee, pad bulletproofs, fixed 11 ring size
Diffstat (limited to 'src/cryptonote_core/blockchain.cpp')
-rw-r--r--src/cryptonote_core/blockchain.cpp297
1 files changed, 175 insertions, 122 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 9beb28fbd..6fe4a287f 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -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 (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;
+ }
- if (median_block_size < min_block_size)
- median_block_size = min_block_size;
+ const uint64_t fee_base = version >= 5 ? DYNAMIC_FEE_PER_KB_BASE_FEE_V5 : DYNAMIC_FEE_PER_KB_BASE_FEE;
- 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);
+ 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)
- {
- fee_per_kb = FEE_PER_KB;
- }
- else
+ uint64_t median = 0;
+ uint64_t already_generated_coins = 0;
+ uint64_t base_reward = 0;
+ if (version >= HF_VERSION_DYNAMIC_FEE)
{
- 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;
+ 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;
- fee_per_kb = get_dynamic_per_kb_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;
+ 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 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");
+
+ 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);
}
}
}