mirror of
https://github.com/monero-project/monero.git
synced 2025-07-27 22:05:27 -04:00
v8: per byte fee, pad bulletproofs, fixed 11 ring size
This commit is contained in:
parent
869b3bf824
commit
5ffb2ff9b7
55 changed files with 1241 additions and 878 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue