//--------------------------------------------------------------------------------- //proper tx_pool handling courtesy of CryptoZoidberg and Boolberry bool tx_memory_pool::remove_stuck_transactions() { CRITICAL_REGION_LOCAL(m_transactions_lock); for(auto it = m_transactions.begin(); it!= m_transactions.end();) { uint64_t tx_age = time(nullptr) - it->second.receive_time; if((tx_age > CRYPTONOTE_MEMPOOL_TX_LIVETIME && !it->second.kept_by_block) || (tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && it->second.kept_by_block) ) { LOG_PRINT_L1("Tx " << it->first << " removed from tx pool due to outdated, age: " << tx_age ); remove_transaction_keyimages(it->second.tx); auto sorted_it = find_tx_in_sorted_container(it->first); if (sorted_it == m_txs_by_fee.end()) { LOG_PRINT_L1("Removing tx " << it->first << " from tx pool, but it was not found in the sorted txs container!"); } else { m_txs_by_fee.erase(sorted_it); } m_transactions.erase(it++); }else ++it; } return true; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee) { CRITICAL_REGION_LOCAL(m_transactions_lock); auto it = m_transactions.find(id); if(it == m_transactions.end()) return false; tx = it->second.tx; blob_size = it->second.blob_size; fee = it->second.fee; remove_transaction_keyimages(it->second.tx); m_transactions.erase(it); return true; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::remove_stuck_transactions() { LOG_PRINT_L2("tx_memory_pool::remove_stuck_transactions()"); CRITICAL_REGION_LOCAL(m_transactions_lock); for (auto it = m_transactions.begin(); it != m_transactions.end();) { uint64_t tx_age = time(nullptr) - it->second.receive_time; if ((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME && !it->second.kept_by_block) || (tx_age > CURRENCY_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && it->second.kept_by_block)) { LOG_PRINT_L0("Tx " << it->first << " removed from tx pool due to outdated, age: " << tx_age); remove_alias_tx_pair(it->first); remove_transaction_keyimages(it->second.tx); m_transactions.erase(it++); } else ++it; } return true; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::init(const std::string& config_folder) { CRITICAL_REGION_LOCAL(m_transactions_lock); m_config_folder = config_folder; std::string state_file_path = config_folder + "/" + CRYPTONOTE_POOLDATA_FILENAME; boost::system::error_code ec; if(!boost::filesystem::exists(state_file_path, ec)) return true; bool res = tools::unserialize_obj_from_file(*this, state_file_path); if(!res) { LOG_PRINT_L1("Failed to load memory pool from file " << state_file_path); m_transactions.clear(); m_txs_by_fee.clear(); m_spent_key_images.clear(); } for (auto it = m_transactions.begin(); it != m_transactions.end(); ) { if (it->second.blob_size >= TRANSACTION_SIZE_LIMIT) { LOG_PRINT_L1("Transaction " << get_transaction_hash(it->second.tx) << " is too big (" << it->second.blob_size << " bytes), removing it from pool"); remove_transaction_keyimages(it->second.tx); m_transactions.erase(it); } it++; } // no need to store queue of sorted transactions, as it's easy to generate. for (const auto& tx : m_transactions) { m_txs_by_fee.emplace((double)tx.second.blob_size / tx.second.fee, tx.first); } // Ignore deserialization error return true; }