1
0
Fork 0
forked from lthn/blockchain

transaction pool optimisation: basic implemntation

This commit is contained in:
cryptozoidberg 2019-11-16 01:06:21 +01:00
parent 499f822e97
commit 17e36012de
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
7 changed files with 56 additions and 35 deletions

View file

@ -439,7 +439,7 @@ bool blockchain_storage::deinit()
return true; return true;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool blockchain_storage::pop_block_from_blockchain() bool blockchain_storage::pop_block_from_blockchain(transactions_map& onboard_transactions)
{ {
CRITICAL_REGION_LOCAL(m_read_lock); CRITICAL_REGION_LOCAL(m_read_lock);
@ -449,7 +449,7 @@ bool blockchain_storage::pop_block_from_blockchain()
CHECK_AND_ASSERT_MES(bei_ptr.get(), false, "pop_block_from_blockchain: can't pop from blockchain"); CHECK_AND_ASSERT_MES(bei_ptr.get(), false, "pop_block_from_blockchain: can't pop from blockchain");
uint64_t fee_total = 0; uint64_t fee_total = 0;
bool r = purge_block_data_from_blockchain(bei_ptr->bl, bei_ptr->bl.tx_hashes.size(), fee_total); bool r = purge_block_data_from_blockchain(bei_ptr->bl, bei_ptr->bl.tx_hashes.size(), fee_total, onboard_transactions);
CHECK_AND_ASSERT_MES(r, false, "Failed to purge_block_data_from_blockchain for block " << get_block_hash(bei_ptr->bl) << " on height " << h); CHECK_AND_ASSERT_MES(r, false, "Failed to purge_block_data_from_blockchain for block " << get_block_hash(bei_ptr->bl) << " on height " << h);
pop_block_from_per_block_increments(bei_ptr->height); pop_block_from_per_block_increments(bei_ptr->height);
@ -649,7 +649,7 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans
return true; return true;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee) bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee, transaction& tx_)
{ {
fee = 0; fee = 0;
CRITICAL_REGION_LOCAL(m_read_lock); CRITICAL_REGION_LOCAL(m_read_lock);
@ -657,6 +657,7 @@ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& t
auto tx_res_ptr = m_db_transactions.find(tx_id); auto tx_res_ptr = m_db_transactions.find(tx_id);
CHECK_AND_ASSERT_MES(tx_res_ptr != m_db_transactions.end(), false, "transaction " << tx_id << " is not found in blockchain index!!"); CHECK_AND_ASSERT_MES(tx_res_ptr != m_db_transactions.end(), false, "transaction " << tx_id << " is not found in blockchain index!!");
const transaction& tx = tx_res_ptr->tx; const transaction& tx = tx_res_ptr->tx;
tx_ = tx;
fee = get_tx_fee(tx_res_ptr->tx); fee = get_tx_fee(tx_res_ptr->tx);
purge_transaction_keyimages_from_blockchain(tx, true); purge_transaction_keyimages_from_blockchain(tx, true);
@ -687,10 +688,11 @@ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& t
bool blockchain_storage::purge_block_data_from_blockchain(const block& b, size_t processed_tx_count) bool blockchain_storage::purge_block_data_from_blockchain(const block& b, size_t processed_tx_count)
{ {
uint64_t total_fee = 0; uint64_t total_fee = 0;
return purge_block_data_from_blockchain(b, processed_tx_count, total_fee); transactions_map onboard_transactions;
return purge_block_data_from_blockchain(b, processed_tx_count, total_fee, onboard_transactions);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_t processed_tx_count, uint64_t& fee_total) bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_t processed_tx_count, uint64_t& fee_total, transactions_map& onboard_transactions)
{ {
CRITICAL_REGION_LOCAL(m_read_lock); CRITICAL_REGION_LOCAL(m_read_lock);
fee_total = 0; fee_total = 0;
@ -699,11 +701,13 @@ bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_
CHECK_AND_ASSERT_MES(processed_tx_count <= bl.tx_hashes.size(), false, "wrong processed_tx_count in purge_block_data_from_blockchain"); CHECK_AND_ASSERT_MES(processed_tx_count <= bl.tx_hashes.size(), false, "wrong processed_tx_count in purge_block_data_from_blockchain");
for(size_t count = 0; count != processed_tx_count; count++) for(size_t count = 0; count != processed_tx_count; count++)
{ {
res = purge_transaction_from_blockchain(bl.tx_hashes[(processed_tx_count -1)- count], fee) && res; transaction tx = AUTO_VAL_INIT(tx);
res = purge_transaction_from_blockchain(bl.tx_hashes[(processed_tx_count -1)- count], fee, tx) && res;
fee_total += fee; fee_total += fee;
onboard_transactions[bl.tx_hashes[(processed_tx_count - 1) - count]] = tx;
} }
transaction tx = AUTO_VAL_INIT(tx);
res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee) && res; res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee, tx) && res;
return res; return res;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -866,20 +870,22 @@ bool blockchain_storage::get_block_by_height(uint64_t h, block &blk) const
// invalid.push_back(v.first); // invalid.push_back(v.first);
// } // }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool blockchain_storage::rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height) bool blockchain_storage::rollback_blockchain_switching(std::list<block_ws_txs>& original_chain, size_t rollback_height)
{ {
CRITICAL_REGION_LOCAL(m_read_lock); CRITICAL_REGION_LOCAL(m_read_lock);
//remove failed subchain //remove failed subchain
for(size_t i = m_db_blocks.size()-1; i >=rollback_height; i--) for(size_t i = m_db_blocks.size()-1; i >=rollback_height; i--)
{ {
bool r = pop_block_from_blockchain(); transactions_map ot;
bool r = pop_block_from_blockchain(ot);
CHECK_AND_ASSERT_MES(r, false, "PANIC!!! failed to remove block while chain switching during the rollback!"); CHECK_AND_ASSERT_MES(r, false, "PANIC!!! failed to remove block while chain switching during the rollback!");
} }
//return back original chain //return back original chain
BOOST_FOREACH(auto& bl, original_chain) BOOST_FOREACH(auto& oce, original_chain)
{ {
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
bool r = handle_block_to_main_chain(bl, bvc); bvc.m_onboard_transactions.swap(oce.onboard_transactions);
bool r = handle_block_to_main_chain(oce.b, bvc);
CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC!!! failed to add (again) block while chain switching during the rollback!"); CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC!!! failed to add (again) block while chain switching during the rollback!");
} }
@ -942,13 +948,15 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
); );
//disconnecting old chain //disconnecting old chain
std::list<block> disconnected_chain; std::list<block_ws_txs> disconnected_chain;
for(size_t i = m_db_blocks.size()-1; i >=split_height; i--) for(size_t i = m_db_blocks.size()-1; i >=split_height; i--)
{ {
block b = m_db_blocks[i]->bl; disconnected_chain.push_front(block_ws_txs());
bool r = pop_block_from_blockchain(); block_ws_txs& bwt = disconnected_chain.front();
CHECK_AND_ASSERT_MES(r, false, "failed to remove block " << get_block_hash(b) << " @ " << get_block_height(b) << " on chain switching"); bwt.b = m_db_blocks[i]->bl;
disconnected_chain.push_front(b); bool r = pop_block_from_blockchain(bwt.onboard_transactions);
CHECK_AND_ASSERT_MES(r, false, "failed to remove block " << get_block_hash(bwt.b) << " @ " << get_block_height(bwt.b) << " on chain switching");
CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!");
} }
@ -957,6 +965,7 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
{ {
auto ch_ent = *alt_ch_iter; auto ch_ent = *alt_ch_iter;
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
bvc.m_onboard_transactions = ch_ent->second.onboard_transactions;
bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc); bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc);
if(!r || !bvc.m_added_to_main_chain) if(!r || !bvc.m_added_to_main_chain)
{ {
@ -978,7 +987,8 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
for(auto& old_ch_ent : disconnected_chain) for(auto& old_ch_ent : disconnected_chain)
{ {
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc); bvc.m_onboard_transactions.swap(old_ch_ent.onboard_transactions);
bool r = handle_alternative_block(old_ch_ent.b, get_block_hash(old_ch_ent.b), bvc);
if(!r) if(!r)
{ {
LOG_ERROR("Failed to push ex-main chain blocks to alternative chain "); LOG_ERROR("Failed to push ex-main chain blocks to alternative chain ");
@ -1602,6 +1612,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
alt_block_extended_info abei = AUTO_VAL_INIT(abei); alt_block_extended_info abei = AUTO_VAL_INIT(abei);
abei.bl = b; abei.bl = b;
abei.onboard_transactions.swap(bvc.m_onboard_transactions);
abei.timestamp = m_core_runtime_config.get_core_time(); abei.timestamp = m_core_runtime_config.get_core_time();
abei.height = alt_chain.size() ? it_prev->second.height + 1 : *ptr_main_prev + 1; abei.height = alt_chain.size() ? it_prev->second.height + 1 : *ptr_main_prev + 1;
CHECK_AND_ASSERT_MES_CUSTOM(coinbase_height == abei.height, false, bvc.m_verification_failed = true, "block coinbase height doesn't match with altchain height, declined"); CHECK_AND_ASSERT_MES_CUSTOM(coinbase_height == abei.height, false, bvc.m_verification_failed = true, "block coinbase height doesn't match with altchain height, declined");
@ -1716,7 +1727,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
alt_chain.push_back(i_res.first); alt_chain.push_back(i_res.first);
//check if difficulty bigger then in main chain //check if difficulty bigger then in main chain
bvc.height_difference = get_top_block_height() >= abei.height ? get_top_block_height() - abei.height : 0; bvc.m_height_difference = get_top_block_height() >= abei.height ? get_top_block_height() - abei.height : 0;
crypto::hash proof = null_hash; crypto::hash proof = null_hash;
std::stringstream ss_pow_pos_info; std::stringstream ss_pow_pos_info;
@ -1753,7 +1764,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
bvc.m_verification_failed = true; bvc.m_verification_failed = true;
return r; return r;
} }
bvc.added_to_altchain = true; bvc.m_added_to_altchain = true;
//protect ourself from altchains container flood //protect ourself from altchains container flood
if (m_alternative_chains.size() > m_core_runtime_config.max_alt_blocks) if (m_alternative_chains.size() > m_core_runtime_config.max_alt_blocks)
@ -4763,7 +4774,7 @@ wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise
return 0; return 0;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool get_tx_from_cache(const crypto::hash& tx_id, std::unordered_map<crypto::hash, transaction>& tx_cache, transaction& tx, size_t& blob_size, uint64_t fee) bool get_tx_from_cache(const crypto::hash& tx_id, transactions_map& tx_cache, transaction& tx, size_t& blob_size, uint64_t fee)
{ {
auto it = tx_cache.find(tx_id); auto it = tx_cache.find(tx_id);
if (it == tx_cache.end()) if (it == tx_cache.end())
@ -5344,7 +5355,8 @@ bool blockchain_storage::truncate_blockchain(uint64_t to_height)
uint64_t inital_height = get_current_blockchain_size(); uint64_t inital_height = get_current_blockchain_size();
while (get_current_blockchain_size() > to_height) while (get_current_blockchain_size() > to_height)
{ {
pop_block_from_blockchain(); transactions_map ot;
pop_block_from_blockchain(ot);
} }
CRITICAL_REGION_LOCAL(m_alternative_chains_lock); CRITICAL_REGION_LOCAL(m_alternative_chains_lock);
m_alternative_chains.clear(); m_alternative_chains.clear();

View file

@ -156,6 +156,9 @@ namespace currency
//date added to alt chain storage //date added to alt chain storage
uint64_t timestamp; uint64_t timestamp;
//transactions associated with the block
transactions_map onboard_transactions;
}; };
typedef std::unordered_map<crypto::hash, alt_block_extended_info> alt_chain_container; typedef std::unordered_map<crypto::hash, alt_block_extended_info> alt_chain_container;
//typedef std::list<alt_chain_container::iterator> alt_chain_type; //typedef std::list<alt_chain_container::iterator> alt_chain_type;
@ -543,10 +546,10 @@ namespace currency
bool switch_to_alternative_blockchain(alt_chain_type& alt_chain); bool switch_to_alternative_blockchain(alt_chain_type& alt_chain);
void purge_alt_block_txs_hashs(const block& b); void purge_alt_block_txs_hashs(const block& b);
void add_alt_block_txs_hashs(const block& b); void add_alt_block_txs_hashs(const block& b);
bool pop_block_from_blockchain(); bool pop_block_from_blockchain(transactions_map& onboard_transactions);
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count); bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count);
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count, uint64_t& fee); bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count, uint64_t& fee, transactions_map& onboard_transactions);
bool purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee); bool purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee, transaction& tx);
bool purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check); bool purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check);
wide_difficulty_type get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const; wide_difficulty_type get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const;
bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc);
@ -565,7 +568,7 @@ namespace currency
bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr<transaction>& tx_ptr, uint64_t min_allowed_block_height = 0) const; bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr<transaction>& tx_ptr, uint64_t min_allowed_block_height = 0) const;
void get_last_n_x_blocks(uint64_t n, bool pos_blocks, std::list<std::shared_ptr<const block_extended_info>>& blocks) const; void get_last_n_x_blocks(uint64_t n, bool pos_blocks, std::list<std::shared_ptr<const block_extended_info>>& blocks) const;
bool prevalidate_miner_transaction(const block& b, uint64_t height, bool pos)const; bool prevalidate_miner_transaction(const block& b, uint64_t height, bool pos)const;
bool rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height); bool rollback_blockchain_switching(std::list<block_ws_txs>& original_chain, size_t rollback_height);
bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp); bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp);
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes); bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id);

View file

@ -145,6 +145,12 @@ namespace currency
uint64_t height; uint64_t height;
}; };
typedef std::unordered_map<crypto::hash, transaction> transactions_map;
struct block_ws_txs
{
block b;
transactions_map onboard_transactions;
};
} }

View file

@ -25,11 +25,11 @@ namespace currency
bool m_verification_failed; //bad block, should drop connection bool m_verification_failed; //bad block, should drop connection
bool m_marked_as_orphaned; bool m_marked_as_orphaned;
bool m_already_exists; bool m_already_exists;
bool added_to_altchain; bool m_added_to_altchain;
uint64_t height_difference; uint64_t m_height_difference;
//this is work like a first-level cache for transactions while block is getting handled. It lets transactions //this is work like a first-level cache for transactions while block is getting handled. It lets transactions
//associated with the block to get handled directly to core without being handled by tx_pool(which makes full //associated with the block to get handled directly to core without being handled by tx_pool(which makes full
//inputs validation, including signatures check) //inputs validation, including signatures check)
std::unordered_map<crypto::hash, transaction> m_onboard_transactions; transactions_map m_onboard_transactions;
}; };
} }

View file

@ -327,10 +327,10 @@ namespace currency
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA " << block_id LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA " << block_id
<< " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain << " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain
//<< ", prevalidate_result=" << prevalidate_relayed //<< ", prevalidate_result=" << prevalidate_relayed
<< ", bvc.added_to_altchain=" << bvc.added_to_altchain << ", bvc.added_to_altchain=" << bvc.m_added_to_altchain
<< ", bvc.m_marked_as_orphaned=" << bvc.m_marked_as_orphaned, LOG_LEVEL_2); << ", bvc.m_marked_as_orphaned=" << bvc.m_marked_as_orphaned, LOG_LEVEL_2);
if (bvc.m_added_to_main_chain || (bvc.added_to_altchain && bvc.height_difference < 2)) if (bvc.m_added_to_main_chain || (bvc.m_added_to_altchain && bvc.m_height_difference < 2))
{ {
if (true/*!prevalidate_relayed*/) if (true/*!prevalidate_relayed*/)
{ {

View file

@ -851,7 +851,7 @@ namespace currency
block_verification_context bvc = AUTO_VAL_INIT(bvc); block_verification_context bvc = AUTO_VAL_INIT(bvc);
if(!m_core.handle_block_found(b, &bvc)) if(!m_core.handle_block_found(b, &bvc))
{ {
if (bvc.added_to_altchain) if (bvc.m_added_to_altchain)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_ADDED_AS_ALTERNATIVE; error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_ADDED_AS_ALTERNATIVE;
error_resp.message = "Block added as alternative"; error_resp.message = "Block added as alternative";

View file

@ -532,7 +532,7 @@ namespace
r = m_p_core->handle_block_found(m_block_template, &bvc, false); r = m_p_core->handle_block_found(m_block_template, &bvc, false);
if (r) if (r)
{ {
if (!bvc.m_verification_failed && !bvc.added_to_altchain && bvc.m_added_to_main_chain && !bvc.m_already_exists && !bvc.m_marked_as_orphaned) if (!bvc.m_verification_failed && !bvc.m_added_to_altchain && bvc.m_added_to_main_chain && !bvc.m_already_exists && !bvc.m_marked_as_orphaned)
{ {
LP_CC_WORKER_GREEN(p_ph->get_context(), "found block " << block_hash << " at height " << height << " was successfully added to the blockchain, difficulty " << m_network_difficulty, LOG_LEVEL_0); LP_CC_WORKER_GREEN(p_ph->get_context(), "found block " << block_hash << " at height " << height << " was successfully added to the blockchain, difficulty " << m_network_difficulty, LOG_LEVEL_0);
r = update_block_template(); r = update_block_template();
@ -544,7 +544,7 @@ namespace
{ {
LP_CC_WORKER_RED(p_ph->get_context(), "block " << block_hash << " at height " << height << " was NOT added to the blockchain:" << ENDL << LP_CC_WORKER_RED(p_ph->get_context(), "block " << block_hash << " at height " << height << " was NOT added to the blockchain:" << ENDL <<
" verification_failed: " << bvc.m_verification_failed << ENDL << " verification_failed: " << bvc.m_verification_failed << ENDL <<
" added_to_altchain: " << bvc.added_to_altchain << ENDL << " added_to_altchain: " << bvc.m_added_to_altchain << ENDL <<
" added_to_main_chain: " << bvc.m_added_to_main_chain << ENDL << " added_to_main_chain: " << bvc.m_added_to_main_chain << ENDL <<
" already_exists: " << bvc.m_already_exists << ENDL << " already_exists: " << bvc.m_already_exists << ENDL <<
" marked_as_orphaned: " << bvc.m_marked_as_orphaned, LOG_LEVEL_0); " marked_as_orphaned: " << bvc.m_marked_as_orphaned, LOG_LEVEL_0);