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;
}
//------------------------------------------------------------------
bool blockchain_storage::pop_block_from_blockchain()
bool blockchain_storage::pop_block_from_blockchain(transactions_map& onboard_transactions)
{
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");
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);
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;
}
//------------------------------------------------------------------
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;
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);
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;
tx_ = tx;
fee = get_tx_fee(tx_res_ptr->tx);
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)
{
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);
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");
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;
onboard_transactions[bl.tx_hashes[(processed_tx_count - 1) - count]] = tx;
}
res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee) && res;
transaction tx = AUTO_VAL_INIT(tx);
res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee, tx) && 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);
// }
//------------------------------------------------------------------
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);
//remove failed subchain
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!");
}
//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>();
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!");
}
@ -942,13 +948,15 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
);
//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--)
{
block b = m_db_blocks[i]->bl;
bool r = pop_block_from_blockchain();
CHECK_AND_ASSERT_MES(r, false, "failed to remove block " << get_block_hash(b) << " @ " << get_block_height(b) << " on chain switching");
disconnected_chain.push_front(b);
disconnected_chain.push_front(block_ws_txs());
block_ws_txs& bwt = disconnected_chain.front();
bwt.b = m_db_blocks[i]->bl;
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!");
}
@ -957,6 +965,7 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
{
auto ch_ent = *alt_ch_iter;
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);
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)
{
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)
{
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);
abei.bl = b;
abei.onboard_transactions.swap(bvc.m_onboard_transactions);
abei.timestamp = m_core_runtime_config.get_core_time();
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");
@ -1716,7 +1727,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
alt_chain.push_back(i_res.first);
//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;
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;
return r;
}
bvc.added_to_altchain = true;
bvc.m_added_to_altchain = true;
//protect ourself from altchains container flood
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;
}
//------------------------------------------------------------------
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);
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();
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);
m_alternative_chains.clear();

View file

@ -156,6 +156,9 @@ namespace currency
//date added to alt chain storage
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::list<alt_chain_container::iterator> alt_chain_type;
@ -543,10 +546,10 @@ namespace currency
bool switch_to_alternative_blockchain(alt_chain_type& alt_chain);
void purge_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, uint64_t& fee);
bool purge_transaction_from_blockchain(const crypto::hash& tx_id, 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, transaction& tx);
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;
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;
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 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 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);

View file

@ -145,6 +145,12 @@ namespace currency
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_marked_as_orphaned;
bool m_already_exists;
bool added_to_altchain;
uint64_t height_difference;
bool m_added_to_altchain;
uint64_t m_height_difference;
//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
//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
<< " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain
//<< ", 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);
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*/)
{

View file

@ -851,7 +851,7 @@ namespace currency
block_verification_context bvc = AUTO_VAL_INIT(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.message = "Block added as alternative";

View file

@ -532,7 +532,7 @@ namespace
r = m_p_core->handle_block_found(m_block_template, &bvc, false);
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);
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 <<
" 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 <<
" already_exists: " << bvc.m_already_exists << ENDL <<
" marked_as_orphaned: " << bvc.m_marked_as_orphaned, LOG_LEVEL_0);