tx_pool: better block template filling algorithm

Continue filling until we reach the block size limit, or the
resulting coinbase decreases.

Also remove old sanity check on block size, which is now not
wanted anymore.
This commit is contained in:
moneromooo-monero 2017-01-06 20:34:37 +00:00
parent 9731b4e54f
commit 1607cb7e0c
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
3 changed files with 36 additions and 20 deletions

View File

@ -1084,7 +1084,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
size_t txs_size; size_t txs_size;
uint64_t fee; uint64_t fee;
if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee, m_hardfork->get_current_version()))
{ {
return false; return false;
} }

View File

@ -60,6 +60,7 @@ namespace cryptonote
size_t const TRANSACTION_SIZE_LIMIT_V2 = (((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); size_t const TRANSACTION_SIZE_LIMIT_V2 = (((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
time_t const MIN_RELAY_TIME = (60 * 5); // only start re-relaying transactions after that many seconds time_t const MIN_RELAY_TIME = (60 * 5); // only start re-relaying transactions after that many seconds
time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
float const ACCEPT_THRESHOLD = 0.99f;
// a kind of increasing backoff within min/max bounds // a kind of increasing backoff within min/max bounds
time_t get_relay_delay(time_t now, time_t received) time_t get_relay_delay(time_t now, time_t received)
@ -69,6 +70,11 @@ namespace cryptonote
d = MAX_RELAY_TIME; d = MAX_RELAY_TIME;
return d; return d;
} }
uint64_t template_accept_threshold(uint64_t amount)
{
return amount * ACCEPT_THRESHOLD;
}
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -585,7 +591,7 @@ namespace cryptonote
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate //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) 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, uint8_t version)
{ {
// Warning: This function takes already_generated_ // Warning: This function takes already_generated_
// coins as an argument and appears to do nothing // coins as an argument and appears to do nothing
@ -593,47 +599,51 @@ namespace cryptonote
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
uint64_t best_coinbase = 0;
total_size = 0; total_size = 0;
fee = 0; fee = 0;
// Maximum block size is 130% of the median block size. This gives a size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
// little extra headroom for the max size transaction.
size_t max_total_size = (130 * median_size) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
std::unordered_set<crypto::key_image> k_images; std::unordered_set<crypto::key_image> k_images;
LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee.size() << " txes in the pool");
auto sorted_it = m_txs_by_fee.begin(); auto sorted_it = m_txs_by_fee.begin();
while (sorted_it != m_txs_by_fee.end()) while (sorted_it != m_txs_by_fee.end())
{ {
auto tx_it = m_transactions.find(sorted_it->second); auto tx_it = m_transactions.find(sorted_it->second);
LOG_PRINT_L2("Considering " << tx_it->first << ", size " << tx_it->second.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase));
// Can not exceed maximum block size // Can not exceed maximum block size
if (max_total_size < total_size + tx_it->second.blob_size) if (max_total_size < total_size + tx_it->second.blob_size)
{ {
LOG_PRINT_L2(" would exceed maximum block size");
sorted_it++; sorted_it++;
continue; continue;
} }
// If adding this tx will make the block size // If we're getting lower coinbase tx,
// greater than CRYPTONOTE_GETBLOCKTEMPLATE_MAX
// _BLOCK_SIZE bytes, reject the tx; this will
// keep block sizes from becoming too unwieldly
// to propagate at 60s block times.
if ( (total_size + tx_it->second.blob_size) > CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE )
{
sorted_it++;
continue;
}
// If we've exceeded the penalty free size,
// stop including more tx // stop including more tx
if (total_size > median_size) uint64_t block_reward;
break; if(!get_block_reward(median_size, total_size + tx_it->second.blob_size, already_generated_coins, block_reward, version))
{
LOG_PRINT_L2(" would exceed maximum block size");
sorted_it++;
continue;
}
uint64_t coinbase = block_reward + fee;
if (coinbase < template_accept_threshold(best_coinbase))
{
LOG_PRINT_L2(" would decrease coinbase to " << print_money(coinbase));
sorted_it++;
continue;
}
// Skip transactions that are not ready to be // Skip transactions that are not ready to be
// included into the blockchain or that are // included into the blockchain or that are
// missing key images // missing key images
if (!is_transaction_ready_to_go(tx_it->second) || have_key_images(k_images, tx_it->second.tx)) if (!is_transaction_ready_to_go(tx_it->second) || have_key_images(k_images, tx_it->second.tx))
{ {
LOG_PRINT_L2(" not ready to go, or key images already seen");
sorted_it++; sorted_it++;
continue; continue;
} }
@ -641,10 +651,15 @@ namespace cryptonote
bl.tx_hashes.push_back(tx_it->first); bl.tx_hashes.push_back(tx_it->first);
total_size += tx_it->second.blob_size; total_size += tx_it->second.blob_size;
fee += tx_it->second.fee; fee += tx_it->second.fee;
best_coinbase = coinbase;
append_key_images(k_images, tx_it->second.tx); append_key_images(k_images, tx_it->second.tx);
sorted_it++; sorted_it++;
LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(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)
<< " (including " << print_money(fee) << " in fees)");
return true; return true;
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------

View File

@ -216,10 +216,11 @@ namespace cryptonote
* @param already_generated_coins the current total number of coins "minted" * @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_size return-by-reference the total size of the new block
* @param fee return-by-reference the total of fees from the included transactions * @param fee return-by-reference the total of fees from the included transactions
* @param version hard fork version to use for consensus rules
* *
* @return true * @return true
*/ */
bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee); bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint8_t version);
/** /**
* @brief get a list of all transactions in the pool * @brief get a list of all transactions in the pool