aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
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
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')
-rw-r--r--src/cryptonote_core/blockchain.cpp297
-rw-r--r--src/cryptonote_core/blockchain.h77
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp88
-rw-r--r--src/cryptonote_core/cryptonote_core.h4
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp6
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp163
-rw-r--r--src/cryptonote_core/tx_pool.h46
8 files changed, 356 insertions, 327 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);
}
}
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 2292ffbf3..7e2ba7a39 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -95,7 +95,7 @@ namespace cryptonote
{
block bl; //!< the block
uint64_t height; //!< the height of the block in the blockchain
- size_t block_cumulative_size; //!< the size (in bytes) of the block
+ size_t block_cumulative_weight; //!< the weight of the block
difficulty_type cumulative_difficulty; //!< the accumulated difficulty after that block
uint64_t already_generated_coins; //!< the total coins minted after that block
};
@@ -579,46 +579,57 @@ namespace cryptonote
bool check_tx_inputs(transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false);
/**
- * @brief get dynamic per kB fee for a given block size
+ * @brief get fee quantization mask
*
- * The dynamic fee is based on the block size in a past window, and
- * the current block reward. It is expressed by kB.
+ * The dynamic fee may be quantized, to mask out the last decimal places
+ *
+ * @return the fee quantized mask
+ */
+ static uint64_t get_fee_quantization_mask();
+
+ /**
+ * @brief get dynamic per kB or byte fee for a given block weight
+ *
+ * The dynamic fee is based on the block weight in a past window, and
+ * the current block reward. It is expressed by kB before v8, and
+ * per byte from v8.
*
* @param block_reward the current block reward
- * @param median_block_size the median blob's size in the past window
+ * @param median_block_weight the median block weight in the past window
* @param version hard fork version for rules and constants to use
*
- * @return the per kB fee
+ * @return the fee
*/
- static uint64_t get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size, uint8_t version);
+ static uint64_t get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version);
/**
- * @brief get dynamic per kB fee estimate for the next few blocks
+ * @brief get dynamic per kB or byte fee estimate for the next few blocks
*
- * The dynamic fee is based on the block size in a past window, and
- * the current block reward. It is expressed by kB. This function
- * calculates an estimate for a dynamic fee which will be valid for
- * the next grace_blocks
+ * The dynamic fee is based on the block weight in a past window, and
+ * the current block reward. It is expressed by kB before v8, and
+ * per byte from v8.
+ * This function calculates an estimate for a dynamic fee which will be
+ * valid for the next grace_blocks
*
* @param grace_blocks number of blocks we want the fee to be valid for
*
- * @return the per kB fee estimate
+ * @return the fee estimate
*/
- uint64_t get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) const;
+ uint64_t get_dynamic_base_fee_estimate(uint64_t grace_blocks) const;
/**
* @brief validate a transaction's fee
*
* This function validates the fee is enough for the transaction.
- * This is based on the size of the transaction blob, and, after a
- * height threshold, on the average size of transaction in a past window
+ * This is based on the weight of the transaction, and, after a
+ * height threshold, on the average weight of transaction in a past window
*
- * @param blob_size the transaction blob's size
+ * @param tx_weight the transaction weight
* @param fee the fee
*
* @return true if the fee is enough, false otherwise
*/
- bool check_fee(size_t blob_size, uint64_t fee) const;
+ bool check_fee(size_t tx_weight, uint64_t fee) const;
/**
* @brief check that a transaction's outputs conform to current standards
@@ -635,18 +646,18 @@ namespace cryptonote
bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc);
/**
- * @brief gets the blocksize limit based on recent blocks
+ * @brief gets the block weight limit based on recent blocks
*
* @return the limit
*/
- uint64_t get_current_cumulative_blocksize_limit() const;
+ uint64_t get_current_cumulative_block_weight_limit() const;
/**
- * @brief gets the blocksize median based on recent blocks (same window as for the limit)
+ * @brief gets the block weight median based on recent blocks (same window as for the limit)
*
* @return the median
*/
- uint64_t get_current_cumulative_blocksize_median() const;
+ uint64_t get_current_cumulative_block_weight_median() const;
/**
* @brief gets the difficulty of the block with a given height
@@ -1001,8 +1012,8 @@ namespace cryptonote
// main chain
transactions_container m_transactions;
- size_t m_current_block_cumul_sz_limit;
- size_t m_current_block_cumul_sz_median;
+ size_t m_current_block_cumul_weight_limit;
+ size_t m_current_block_cumul_weight_median;
// metadata containers
std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>> m_scan_table;
@@ -1225,7 +1236,7 @@ namespace cryptonote
* and that his miner transaction totals reward + fee.
*
* @param b the block containing the miner transaction to be validated
- * @param cumulative_block_size the block's size
+ * @param cumulative_block_weight the block's weight
* @param fee the total fees collected in the block
* @param base_reward return-by-reference the new block's generated coins
* @param already_generated_coins the amount of currency generated prior to this block
@@ -1234,7 +1245,7 @@ namespace cryptonote
*
* @return false if anything is found wrong with the miner transaction, otherwise true
*/
- bool 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 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);
/**
* @brief reverts the blockchain to its previous state following a failed switch
@@ -1251,14 +1262,14 @@ namespace cryptonote
bool rollback_blockchain_switching(std::list<block>& original_chain, uint64_t rollback_height);
/**
- * @brief gets recent block sizes for median calculation
+ * @brief gets recent block weights for median calculation
*
- * get the block sizes of the last <count> blocks, and return by reference <sz>.
+ * get the block weights of the last <count> blocks, and return by reference <sz>.
*
- * @param sz return-by-reference the list of sizes
- * @param count the number of blocks to get sizes for
+ * @param sz return-by-reference the list of weights
+ * @param count the number of blocks to get weights for
*/
- void get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count) const;
+ void get_last_n_blocks_weights(std::vector<size_t>& weights, size_t count) const;
/**
* @brief adds the given output to the requested set of random outputs
@@ -1373,11 +1384,11 @@ namespace cryptonote
bool complete_timestamps_vector(uint64_t start_height, std::vector<uint64_t>& timestamps);
/**
- * @brief calculate the block size limit for the next block to be added
+ * @brief calculate the block weight limit for the next block to be added
*
* @return true
*/
- bool update_next_cumulative_size_limit();
+ bool update_next_cumulative_weight_limit();
void return_tx_to_pool(std::vector<transaction> &txs);
/**
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index f9e0b68d0..c4eaa0cc4 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -162,10 +162,10 @@ namespace cryptonote
, "Relay blocks as normal blocks"
, false
};
- static const command_line::arg_descriptor<size_t> arg_max_txpool_size = {
- "max-txpool-size"
- , "Set maximum txpool size in bytes."
- , DEFAULT_TXPOOL_MAX_SIZE
+ static const command_line::arg_descriptor<size_t> arg_max_txpool_weight = {
+ "max-txpool-weight"
+ , "Set maximum txpool weight in bytes."
+ , DEFAULT_TXPOOL_MAX_WEIGHT
};
//-----------------------------------------------------------------------------------------------
@@ -274,7 +274,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_test_dbg_lock_sleep);
command_line::add_arg(desc, arg_offline);
command_line::add_arg(desc, arg_disable_dns_checkpoints);
- command_line::add_arg(desc, arg_max_txpool_size);
+ command_line::add_arg(desc, arg_max_txpool_weight);
miner::init_options(desc);
BlockchainDB::init_options(desc);
@@ -402,7 +402,7 @@ namespace cryptonote
bool fast_sync = command_line::get_arg(vm, arg_fast_block_sync) != 0;
uint64_t blocks_threads = command_line::get_arg(vm, arg_prep_blocks_threads);
std::string check_updates_string = command_line::get_arg(vm, arg_check_updates);
- size_t max_txpool_size = command_line::get_arg(vm, arg_max_txpool_size);
+ size_t max_txpool_weight = command_line::get_arg(vm, arg_max_txpool_weight);
boost::filesystem::path folder(m_config_folder);
if (m_nettype == FAKECHAIN)
@@ -551,7 +551,7 @@ namespace cryptonote
const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty);
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty);
- r = m_mempool.init(max_txpool_size);
+ r = m_mempool.init(max_txpool_weight);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
// now that we have a valid m_blockchain_storage, we can clean out any
@@ -692,43 +692,6 @@ namespace cryptonote
return false;
}
- // resolve outPk references in rct txes
- // outPk aren't the only thing that need resolving for a fully resolved tx,
- // but outPk (1) are needed now to check range proof semantics, and
- // (2) do not need access to the blockchain to find data
- if (tx.version >= 2)
- {
- rct::rctSig &rv = tx.rct_signatures;
- if (rv.outPk.size() != tx.vout.size())
- {
- LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected");
- tvc.m_verifivation_failed = true;
- return false;
- }
- for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
- rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
-
- const bool bulletproof = rct::is_rct_bulletproof(rv.type);
- if (bulletproof)
- {
- if (rct::n_bulletproof_amounts(rv.p.bulletproofs) != tx.vout.size())
- {
- LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad bulletproofs size in tx " << tx_hash << ", rejected");
- tvc.m_verifivation_failed = true;
- return false;
- }
- size_t idx = 0;
- for (size_t n = 0; n < rv.p.bulletproofs.size(); ++n)
- {
- CHECK_AND_ASSERT_MES(rv.p.bulletproofs[n].L.size() >= 6, false, "Bad bulletproofs L size"); // at least 64 bits
- const size_t n_amounts = rct::n_bulletproof_amounts(rv.p.bulletproofs[n]);
- CHECK_AND_ASSERT_MES(idx + n_amounts <= rv.outPk.size(), false, "Internal error filling out V");
- rv.p.bulletproofs[n].V.clear();
- for (size_t i = 0; i < n_amounts; ++i)
- rv.p.bulletproofs[n].V.push_back(rv.outPk[idx++].mask);
- }
- }
- }
return true;
}
//-----------------------------------------------------------------------------------------------
@@ -747,20 +710,11 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
static bool is_canonical_bulletproof_layout(const std::vector<rct::Bulletproof> &proofs)
{
- size_t n_amounts = rct::n_bulletproof_amounts(proofs), amounts_proved = 0;
- size_t n = 0;
- while (amounts_proved < n_amounts)
- {
- if (n >= proofs.size())
- return false;
- size_t batch_size = 1;
- while (batch_size * 2 + amounts_proved <= n_amounts && batch_size * 2 <= BULLETPROOF_MAX_OUTPUTS)
- batch_size *= 2;
- if (rct::n_bulletproof_amounts(proofs[n]) != batch_size)
- return false;
- amounts_proved += batch_size;
- ++n;
- }
+ if (proofs.size() != 1)
+ return false;
+ const size_t sz = proofs[0].V.size();
+ if (sz == 0 || sz > BULLETPROOF_MAX_OUTPUTS)
+ return false;
return true;
}
//-----------------------------------------------------------------------------------------------
@@ -816,11 +770,9 @@ namespace cryptonote
}
break;
case rct::RCTTypeBulletproof:
- // in addition to valid bulletproofs, we want multi-out
- // proofs to be in decreasing power of 2 constituents
if (!is_canonical_bulletproof_layout(rv.p.bulletproofs))
{
- MERROR_VER("Bulletproof does not use decreasing power of 2 rule");
+ MERROR_VER("Bulletproof does not have canonical form");
set_semantics_failed(tx_info[n].tx_hash);
tx_info[n].tvc.m_verifivation_failed = true;
tx_info[n].result = false;
@@ -933,7 +885,8 @@ namespace cryptonote
continue;
}
- ok &= add_new_tx(results[i].tx, results[i].hash, results[i].prefix_hash, it->size(), tvc[i], keeped_by_block, relayed, do_not_relay);
+ const size_t weight = get_transaction_weight(results[i].tx, it->size());
+ ok &= add_new_tx(results[i].tx, results[i].hash, results[i].prefix_hash, weight, tvc[i], keeped_by_block, relayed, do_not_relay);
if(tvc[i].m_verifivation_failed)
{MERROR_VER("Transaction verification failed: " << results[i].hash);}
else if(tvc[i].m_verifivation_impossible)
@@ -1016,9 +969,9 @@ namespace cryptonote
}
// for version > 1, ringct signatures check verifies amounts match
- if(!keeped_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_cumulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE)
+ if(!keeped_by_block && get_transaction_weight(tx) >= m_blockchain_storage.get_current_cumulative_block_weight_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE)
{
- MERROR_VER("tx is too large " << get_object_blobsize(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_cumulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
+ MERROR_VER("tx is too large " << get_transaction_weight(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_cumulative_block_weight_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
return false;
}
@@ -1150,7 +1103,8 @@ namespace cryptonote
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
blobdata bl;
t_serializable_object_to_blob(tx, bl);
- return add_new_tx(tx, tx_hash, tx_prefix_hash, bl.size(), tvc, keeped_by_block, relayed, do_not_relay);
+ size_t tx_weight = get_transaction_weight(tx, bl.size());
+ return add_new_tx(tx, tx_hash, tx_prefix_hash, tx_weight, tvc, keeped_by_block, relayed, do_not_relay);
}
//-----------------------------------------------------------------------------------------------
size_t core::get_blockchain_total_transactions() const
@@ -1158,7 +1112,7 @@ namespace cryptonote
return m_blockchain_storage.get_total_transactions();
}
//-----------------------------------------------------------------------------------------------
- bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{
if (keeped_by_block)
get_blockchain_storage().on_new_tx_from_block(tx);
@@ -1176,7 +1130,7 @@ namespace cryptonote
}
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
- return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version);
+ return m_mempool.add_tx(tx, tx_hash, tx_weight, tvc, keeped_by_block, relayed, do_not_relay, version);
}
//-----------------------------------------------------------------------------------------------
bool core::relay_txpool_transactions()
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 497b16214..8b68f5e2b 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -788,12 +788,12 @@ namespace cryptonote
*
* @param tx_hash the transaction's hash
* @param tx_prefix_hash the transaction prefix' hash
- * @param blob_size the size of the transaction
+ * @param tx_weight the weight of the transaction
* @param relayed whether or not the transaction was relayed to us
* @param do_not_relay whether to prevent the transaction from being relayed
*
*/
- bool add_new_tx(transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool add_new_tx(transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
/**
* @brief add a new transaction to the transaction pool
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 525945079..fb2af9ceb 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -74,7 +74,7 @@ namespace cryptonote
LOG_PRINT_L2("destinations include " << num_stdaddresses << " standard addresses and " << num_subaddresses << " subaddresses");
}
//---------------------------------------------------------------
- bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
+ bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
tx.vin.clear();
tx.vout.clear();
tx.extra.clear();
@@ -89,7 +89,7 @@ namespace cryptonote
in.height = height;
uint64_t block_reward;
- if(!get_block_reward(median_size, current_block_size, already_generated_coins, block_reward, hard_fork_version))
+ if(!get_block_reward(median_weight, current_block_weight, already_generated_coins, block_reward, hard_fork_version))
{
LOG_PRINT_L0("Block is too big");
return false;
@@ -491,7 +491,7 @@ namespace cryptonote
// the non-simple version is slightly smaller, but assumes all real inputs
// are on the same index, so can only be used if there just one ring.
- bool use_simple_rct = sources.size() > 1 || range_proof_type == rct::RangeProofMultiOutputBulletproof || range_proof_type == rct::RangeProofBulletproof;
+ bool use_simple_rct = sources.size() > 1 || range_proof_type != rct::RangeProofBorromean;
if (!use_simple_rct)
{
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 08e8725f7..f2cf7b6ca 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -37,7 +37,7 @@
namespace cryptonote
{
//---------------------------------------------------------------
- bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
+ bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
struct tx_source_entry
{
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 41c58fcb6..b12a329bb 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -80,9 +80,13 @@ namespace cryptonote
return amount * ACCEPT_THRESHOLD;
}
- uint64_t get_transaction_size_limit(uint8_t version)
+ uint64_t get_transaction_weight_limit(uint8_t version)
{
- return get_min_block_size(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+ // from v8, limit a tx to 50% of the minimum block weight
+ if (version >= 8)
+ return get_min_block_weight(version) / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+ else
+ return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
}
// This class is meant to create a batch when none currently exists.
@@ -102,12 +106,12 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
- tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_size(DEFAULT_TXPOOL_MAX_SIZE), m_txpool_size(0), m_cookie(0)
+ tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_cookie(0)
{
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
+ bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t tx_weight, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
{
// this should already be called with that lock, but let's make it explicit for clarity
CRITICAL_REGION_LOCAL(m_transactions_lock);
@@ -173,17 +177,17 @@ namespace cryptonote
fee = tx.rct_signatures.txnFee;
}
- if (!kept_by_block && !m_blockchain.check_fee(blob_size, fee))
+ if (!kept_by_block && !m_blockchain.check_fee(tx_weight, fee))
{
tvc.m_verifivation_failed = true;
tvc.m_fee_too_low = true;
return false;
}
- size_t tx_size_limit = get_transaction_size_limit(version);
- if (!kept_by_block && blob_size > tx_size_limit)
+ size_t tx_weight_limit = get_transaction_weight_limit(version);
+ if (!kept_by_block && tx_weight > tx_weight_limit)
{
- LOG_PRINT_L1("transaction is too big: " << blob_size << " bytes, maximum size: " << tx_size_limit);
+ LOG_PRINT_L1("transaction is too heavy: " << tx_weight << " bytes, maximum weight: " << tx_weight_limit);
tvc.m_verifivation_failed = true;
tvc.m_too_big = true;
return false;
@@ -227,7 +231,7 @@ namespace cryptonote
// may become valid again, so ignore the failed inputs check.
if(kept_by_block)
{
- meta.blob_size = blob_size;
+ meta.weight = tx_weight;
meta.fee = fee;
meta.max_used_block_id = null_hash;
meta.max_used_block_height = 0;
@@ -248,7 +252,7 @@ namespace cryptonote
m_blockchain.add_txpool_tx(tx, meta);
if (!insert_key_images(tx, kept_by_block))
return false;
- m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)blob_size, receive_time), id);
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
}
catch (const std::exception &e)
{
@@ -267,7 +271,7 @@ namespace cryptonote
}else
{
//update transactions container
- meta.blob_size = blob_size;
+ meta.weight = tx_weight;
meta.kept_by_block = kept_by_block;
meta.fee = fee;
meta.max_used_block_id = max_used_block_id;
@@ -290,7 +294,7 @@ namespace cryptonote
m_blockchain.add_txpool_tx(tx, meta);
if (!insert_key_images(tx, kept_by_block))
return false;
- m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)blob_size, receive_time), id);
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
}
catch (const std::exception &e)
{
@@ -304,13 +308,13 @@ namespace cryptonote
}
tvc.m_verifivation_failed = false;
- m_txpool_size += blob_size;
+ m_txpool_weight += tx_weight;
++m_cookie;
- MINFO("Transaction added to pool: txid " << id << " bytes: " << blob_size << " fee/byte: " << (fee / (double)blob_size));
+ MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)tx_weight));
- prune(m_txpool_max_size);
+ prune(m_txpool_max_weight);
return true;
}
@@ -321,26 +325,26 @@ namespace cryptonote
size_t blob_size = 0;
if (!get_transaction_hash(tx, h, blob_size) || blob_size == 0)
return false;
- return add_tx(tx, h, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version);
+ return add_tx(tx, h, get_transaction_weight(tx, blob_size), tvc, keeped_by_block, relayed, do_not_relay, version);
}
//---------------------------------------------------------------------------------
- size_t tx_memory_pool::get_txpool_size() const
+ size_t tx_memory_pool::get_txpool_weight() const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
- return m_txpool_size;
+ return m_txpool_weight;
}
//---------------------------------------------------------------------------------
- void tx_memory_pool::set_txpool_max_size(size_t bytes)
+ void tx_memory_pool::set_txpool_max_weight(size_t bytes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
- m_txpool_max_size = bytes;
+ m_txpool_max_weight = bytes;
}
//---------------------------------------------------------------------------------
void tx_memory_pool::prune(size_t bytes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
if (bytes == 0)
- bytes = m_txpool_max_size;
+ bytes = m_txpool_max_weight;
CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain);
bool changed = false;
@@ -349,7 +353,7 @@ namespace cryptonote
auto it = --m_txs_by_fee_and_receive_time.end();
while (it != m_txs_by_fee_and_receive_time.begin())
{
- if (m_txpool_size <= bytes)
+ if (m_txpool_weight <= bytes)
break;
try
{
@@ -374,11 +378,11 @@ namespace cryptonote
return;
}
// remove first, in case this throws, so key images aren't removed
- MINFO("Pruning tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first);
+ MINFO("Pruning tx " << txid << " from txpool: weight: " << it->first.second << ", fee/byte: " << it->first.first);
m_blockchain.remove_txpool_tx(txid);
- m_txpool_size -= txblob.size();
+ m_txpool_weight -= it->first.second;
remove_transaction_keyimages(tx);
- MINFO("Pruned tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first);
+ MINFO("Pruned tx " << txid << " from txpool: weight: " << it->first.second << ", fee/byte: " << it->first.first);
m_txs_by_fee_and_receive_time.erase(it--);
changed = true;
}
@@ -390,8 +394,8 @@ namespace cryptonote
}
if (changed)
++m_cookie;
- if (m_txpool_size > bytes)
- MINFO("Pool size after pruning is larger than limit: " << m_txpool_size << "/" << bytes);
+ if (m_txpool_weight > bytes)
+ MINFO("Pool weight after pruning is larger than limit: " << m_txpool_weight << "/" << bytes);
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::insert_key_images(const transaction &tx, bool kept_by_block)
@@ -446,7 +450,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen)
+ bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -470,7 +474,7 @@ namespace cryptonote
MERROR("Failed to parse tx from txpool");
return false;
}
- blob_size = meta.blob_size;
+ tx_weight = meta.weight;
fee = meta.fee;
relayed = meta.relayed;
do_not_relay = meta.do_not_relay;
@@ -478,7 +482,7 @@ namespace cryptonote
// remove first, in case this throws, so key images aren't removed
m_blockchain.remove_txpool_tx(id);
- m_txpool_size -= blob_size;
+ m_txpool_weight -= tx_weight;
remove_transaction_keyimages(tx);
}
catch (const std::exception &e)
@@ -552,7 +556,7 @@ namespace cryptonote
{
// remove first, so we only remove key images if the tx removal succeeds
m_blockchain.remove_txpool_tx(txid);
- m_txpool_size -= bd.size();
+ m_txpool_weight -= get_transaction_weight(tx, bd.size());
remove_transaction_keyimages(tx);
}
}
@@ -670,7 +674,7 @@ namespace cryptonote
const uint64_t now = time(NULL);
backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
- backlog.push_back({meta.blob_size, meta.fee, meta.receive_time - now});
+ backlog.push_back({meta.weight, meta.fee, meta.receive_time - now});
return true;
}, false, include_unrelayed_txes);
}
@@ -682,15 +686,15 @@ namespace cryptonote
const uint64_t now = time(NULL);
std::map<uint64_t, txpool_histo> agebytes;
stats.txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
- std::vector<uint32_t> sizes;
- sizes.reserve(stats.txs_total);
- m_blockchain.for_all_txpool_txes([&stats, &sizes, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
- sizes.push_back(meta.blob_size);
- stats.bytes_total += meta.blob_size;
- if (!stats.bytes_min || meta.blob_size < stats.bytes_min)
- stats.bytes_min = meta.blob_size;
- if (meta.blob_size > stats.bytes_max)
- stats.bytes_max = meta.blob_size;
+ std::vector<uint32_t> weights;
+ weights.reserve(stats.txs_total);
+ m_blockchain.for_all_txpool_txes([&stats, &weights, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
+ weights.push_back(meta.weight);
+ stats.bytes_total += meta.weight;
+ if (!stats.bytes_min || meta.weight < stats.bytes_min)
+ stats.bytes_min = meta.weight;
+ if (meta.weight > stats.bytes_max)
+ stats.bytes_max = meta.weight;
if (!meta.relayed)
stats.num_not_relayed++;
stats.fee_total += meta.fee;
@@ -702,12 +706,12 @@ namespace cryptonote
stats.num_failing++;
uint64_t age = now - meta.receive_time + (now == meta.receive_time);
agebytes[age].txs++;
- agebytes[age].bytes += meta.blob_size;
+ agebytes[age].bytes += meta.weight;
if (meta.double_spend_seen)
++stats.num_double_spends;
return true;
}, false, include_unrelayed_txes);
- stats.bytes_med = epee::misc_utils::median(sizes);
+ stats.bytes_med = epee::misc_utils::median(weights);
if (stats.txs_total > 1)
{
/* looking for 98th percentile */
@@ -771,7 +775,8 @@ namespace cryptonote
return true;
}
txi.tx_json = obj_to_json_str(tx);
- txi.blob_size = meta.blob_size;
+ txi.blob_size = bd->size();
+ txi.weight = meta.weight;
txi.fee = meta.fee;
txi.kept_by_block = meta.kept_by_block;
txi.max_used_block_height = meta.max_used_block_height;
@@ -842,7 +847,8 @@ namespace cryptonote
return true;
}
txi.tx = tx;
- txi.blob_size = meta.blob_size;
+ txi.blob_size = bd->size();
+ txi.weight = meta.weight;
txi.fee = meta.fee;
txi.kept_by_block = meta.kept_by_block;
txi.max_used_block_height = meta.max_used_block_height;
@@ -1116,7 +1122,8 @@ namespace cryptonote
}
ss << obj_to_json_str(tx) << std::endl;
}
- ss << "blob_size: " << meta.blob_size << std::endl
+ ss << "blob_size: " << (short_format ? "-" : std::to_string(txblob->size())) << std::endl
+ << "weight: " << meta.weight << std::endl
<< "fee: " << print_money(meta.fee) << std::endl
<< "kept_by_block: " << (meta.kept_by_block ? 'T' : 'F') << std::endl
<< "double_spend_seen: " << (meta.double_spend_seen ? 'T' : 'F') << std::endl
@@ -1131,25 +1138,25 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
- bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
+ bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
uint64_t best_coinbase = 0, coinbase = 0;
- total_size = 0;
+ total_weight = 0;
fee = 0;
//baseline empty block
- get_block_reward(median_size, total_size, already_generated_coins, best_coinbase, version);
+ get_block_reward(median_weight, total_weight, already_generated_coins, best_coinbase, version);
- size_t max_total_size_pre_v5 = (130 * median_size) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
- size_t max_total_size_v5 = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
- size_t max_total_size = version >= 5 ? max_total_size_v5 : max_total_size_pre_v5;
+ size_t max_total_weight_pre_v5 = (130 * median_weight) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+ size_t max_total_weight_v5 = 2 * median_weight - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+ size_t max_total_weight = version >= 5 ? max_total_weight_v5 : max_total_weight_pre_v5;
std::unordered_set<crypto::key_image> k_images;
- LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
+ LOG_PRINT_L2("Filling block template, median weight " << median_weight << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
LockedTXN lock(m_blockchain);
@@ -1162,12 +1169,12 @@ namespace cryptonote
MERROR(" failed to find tx meta");
continue;
}
- LOG_PRINT_L2("Considering " << sorted_it->second << ", size " << meta.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase));
+ LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase));
- // Can not exceed maximum block size
- if (max_total_size < total_size + meta.blob_size)
+ // Can not exceed maximum block weight
+ if (max_total_weight < total_weight + meta.weight)
{
- LOG_PRINT_L2(" would exceed maximum block size");
+ LOG_PRINT_L2(" would exceed maximum block weight");
continue;
}
@@ -1177,9 +1184,9 @@ namespace cryptonote
// If we're getting lower coinbase tx,
// stop including more tx
uint64_t block_reward;
- if(!get_block_reward(median_size, total_size + meta.blob_size, already_generated_coins, block_reward, version))
+ if(!get_block_reward(median_weight, total_weight + meta.weight, already_generated_coins, block_reward, version))
{
- LOG_PRINT_L2(" would exceed maximum block size");
+ LOG_PRINT_L2(" would exceed maximum block weight");
continue;
}
coinbase = block_reward + fee + meta.fee;
@@ -1191,11 +1198,11 @@ namespace cryptonote
}
else
{
- // If we've exceeded the penalty free size,
+ // If we've exceeded the penalty free weight,
// stop including more tx
- if (total_size > median_size)
+ if (total_weight > median_weight)
{
- LOG_PRINT_L2(" would exceed median block size");
+ LOG_PRINT_L2(" would exceed median block weight");
break;
}
}
@@ -1241,16 +1248,16 @@ namespace cryptonote
}
bl.tx_hashes.push_back(sorted_it->second);
- total_size += meta.blob_size;
+ total_weight += meta.weight;
fee += meta.fee;
best_coinbase = coinbase;
append_key_images(k_images, tx);
- LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase));
+ LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_money(best_coinbase));
}
expected_reward = best_coinbase;
- LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, size "
- << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase)
+ LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight "
+ << total_weight << "/" << max_total_weight << ", coinbase " << print_money(best_coinbase)
<< " (including " << print_money(fee) << " in fees)");
return true;
}
@@ -1259,14 +1266,14 @@ namespace cryptonote
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- size_t tx_size_limit = get_transaction_size_limit(version);
+ size_t tx_weight_limit = get_transaction_weight_limit(version);
std::unordered_set<crypto::hash> remove;
- m_txpool_size = 0;
- m_blockchain.for_all_txpool_txes([this, &remove, tx_size_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
- m_txpool_size += meta.blob_size;
- if (meta.blob_size > tx_size_limit) {
- LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.blob_size << " bytes), removing it from pool");
+ m_txpool_weight = 0;
+ m_blockchain.for_all_txpool_txes([this, &remove, tx_weight_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
+ m_txpool_weight += meta.weight;
+ if (meta.weight > tx_weight_limit) {
+ LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.weight << " bytes), removing it from pool");
remove.insert(txid);
}
else if (m_blockchain.have_tx(txid)) {
@@ -1293,7 +1300,7 @@ namespace cryptonote
}
// remove tx from db first
m_blockchain.remove_txpool_tx(txid);
- m_txpool_size -= txblob.size();
+ m_txpool_weight -= get_transaction_weight(tx, txblob.size());
remove_transaction_keyimages(tx);
auto sorted_it = find_tx_in_sorted_container(txid);
if (sorted_it == m_txs_by_fee_and_receive_time.end())
@@ -1318,15 +1325,15 @@ namespace cryptonote
return n_removed;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::init(size_t max_txpool_size)
+ bool tx_memory_pool::init(size_t max_txpool_weight)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- m_txpool_max_size = max_txpool_size ? max_txpool_size : DEFAULT_TXPOOL_MAX_SIZE;
+ m_txpool_max_weight = max_txpool_weight ? max_txpool_weight : DEFAULT_TXPOOL_MAX_WEIGHT;
m_txs_by_fee_and_receive_time.clear();
m_spent_key_images.clear();
- m_txpool_size = 0;
+ m_txpool_weight = 0;
std::vector<crypto::hash> remove;
// first add the not kept by block, then the kept by block,
@@ -1348,8 +1355,8 @@ namespace cryptonote
MFATAL("Failed to insert key images from txpool tx");
return false;
}
- m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid);
- m_txpool_size += meta.blob_size;
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.weight, meta.receive_time), txid);
+ m_txpool_weight += meta.weight;
return true;
}, true);
if (!r)
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 4abfef85c..892cadc69 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -84,7 +84,7 @@ namespace cryptonote
*
* This handling includes:
* storing the transactions
- * organizing the transactions by fee per size
+ * organizing the transactions by fee per weight unit
* taking/giving transactions to and from various other components
* saving the transactions to disk on shutdown
* helping create a new block template by choosing transactions for it
@@ -105,9 +105,9 @@ namespace cryptonote
* @copydoc add_tx(transaction&, tx_verification_context&, bool, bool, uint8_t)
*
* @param id the transaction's hash
- * @param blob_size the transaction's size
+ * @param tx_weight the transaction's weight
*/
- bool add_tx(transaction &tx, const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
+ bool add_tx(transaction &tx, const crypto::hash &id, size_t tx_weight, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
/**
* @brief add a transaction to the transaction pool
@@ -133,7 +133,7 @@ namespace cryptonote
*
* @param id the hash of the transaction
* @param tx return-by-reference the transaction taken
- * @param blob_size return-by-reference the transaction's size
+ * @param tx_weight return-by-reference the transaction's weight
* @param fee the transaction fee
* @param relayed return-by-reference was transaction relayed to us by the network?
* @param do_not_relay return-by-reference is transaction not to be relayed to the network?
@@ -141,7 +141,7 @@ namespace cryptonote
*
* @return true unless the transaction cannot be found in the pool
*/
- bool take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen);
+ bool take_tx(const crypto::hash &id, transaction &tx, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen);
/**
* @brief checks if the pool has a transaction with the given hash
@@ -198,11 +198,11 @@ namespace cryptonote
/**
* @brief loads pool state (if any) from disk, and initializes pool
*
- * @param max_txpool_size the max size in bytes
+ * @param max_txpool_weight the max weight in bytes
*
* @return true
*/
- bool init(size_t max_txpool_size = 0);
+ bool init(size_t max_txpool_weight = 0);
/**
* @brief attempts to save the transaction pool state to disk
@@ -219,16 +219,16 @@ namespace cryptonote
* @brief Chooses transactions for a block to include
*
* @param bl return-by-reference the block to fill in with transactions
- * @param median_size the current median block size
+ * @param median_weight the current median block weight
* @param already_generated_coins the current total number of coins "minted"
- * @param total_size return-by-reference the total size of the new block
+ * @param total_weight return-by-reference the total weight of the new block
* @param fee return-by-reference the total of fees from the included transactions
* @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
* @param version hard fork version to use for consensus rules
*
* @return true
*/
- bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t &expected_reward, uint8_t version);
+ bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version);
/**
* @brief get a list of all transactions in the pool
@@ -249,7 +249,7 @@ namespace cryptonote
void get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
/**
- * @brief get (size, fee, receive time) for all transaction in the pool
+ * @brief get (weight, fee, receive time) for all transaction in the pool
*
* @param txs return-by-reference that data
* @param include_unrelayed_txes include unrelayed txes in the result
@@ -370,21 +370,21 @@ namespace cryptonote
uint64_t cookie() const { return m_cookie; }
/**
- * @brief get the cumulative txpool size in bytes
+ * @brief get the cumulative txpool weight in bytes
*
- * @return the cumulative txpool size in bytes
+ * @return the cumulative txpool weight in bytes
*/
- size_t get_txpool_size() const;
+ size_t get_txpool_weight() const;
/**
- * @brief set the max cumulative txpool size in bytes
+ * @brief set the max cumulative txpool weight in bytes
*
- * @param bytes the max cumulative txpool size in bytes
+ * @param bytes the max cumulative txpool weight in bytes
*/
- void set_txpool_max_size(size_t bytes);
+ void set_txpool_max_weight(size_t bytes);
#define CURRENT_MEMPOOL_ARCHIVE_VER 11
-#define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 12
+#define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 13
/**
* @brief information about a single transaction
@@ -393,6 +393,7 @@ namespace cryptonote
{
transaction tx; //!< the transaction
size_t blob_size; //!< the transaction's size
+ size_t weight; //!< the transaction's weight
uint64_t fee; //!< the transaction's fee amount
crypto::hash max_used_block_id; //!< the hash of the highest block referenced by an input
uint64_t max_used_block_height; //!< the height of the highest block referenced by an input
@@ -522,7 +523,7 @@ namespace cryptonote
/**
* @brief prune lowest fee/byte txes till we're not above bytes
*
- * if bytes is 0, use m_txpool_max_size
+ * if bytes is 0, use m_txpool_max_weight
*/
void prune(size_t bytes = 0);
@@ -578,8 +579,8 @@ private:
Blockchain& m_blockchain; //!< reference to the Blockchain object
- size_t m_txpool_max_size;
- size_t m_txpool_size;
+ size_t m_txpool_max_weight;
+ size_t m_txpool_weight;
mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;
};
@@ -608,6 +609,9 @@ namespace boost
if (version < 12)
return;
ar & td.do_not_relay;
+ if (version < 13)
+ return;
+ ar & td.weight;
}
}
}