diff options
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 66 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 6 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 8 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.h | 3 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 35 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.h | 6 |
6 files changed, 78 insertions, 46 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index e908c2012..bfc5dbbe0 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -229,7 +229,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke { try { - m_db->get_output_key(tx_in_to_key.amount, absolute_offsets, outputs, true); + m_db->get_output_key(epee::span<const uint64_t>(&tx_in_to_key.amount, 1), absolute_offsets, outputs, true); if (absolute_offsets.size() != outputs.size()) { MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount); @@ -255,7 +255,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke add_offsets.push_back(absolute_offsets[i]); try { - m_db->get_output_key(tx_in_to_key.amount, add_offsets, add_outputs, true); + m_db->get_output_key(epee::span<const uint64_t>(&tx_in_to_key.amount, 1), add_offsets, add_outputs, true); if (add_offsets.size() != add_outputs.size()) { MERROR_VER("Output does not exist! amount = " << tx_in_to_key.amount); @@ -831,6 +831,7 @@ difficulty_type Blockchain::get_difficulty_for_next_block() std::vector<uint64_t> timestamps; std::vector<difficulty_type> difficulties; auto height = m_db->height(); + top_hash = get_tail_id(); // get it again now that we have the lock // ND: Speedup // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty, // then when the next block difficulty is queried, push the latest height data and @@ -853,7 +854,7 @@ difficulty_type Blockchain::get_difficulty_for_next_block() } else { - size_t offset = height - std::min < size_t > (height, static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT)); + uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT)); if (offset == 0) ++offset; @@ -1766,16 +1767,34 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA res.outs.clear(); res.outs.reserve(req.outputs.size()); + + std::vector<cryptonote::output_data_t> data; try { + std::vector<uint64_t> amounts, offsets; + amounts.reserve(req.outputs.size()); + offsets.reserve(req.outputs.size()); for (const auto &i: req.outputs) { - // get tx_hash, tx_out_index from DB - const output_data_t od = m_db->get_output_key(i.amount, i.index); - tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index); - bool unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)); + amounts.push_back(i.amount); + offsets.push_back(i.index); + } + m_db->get_output_key(epee::span<const uint64_t>(amounts.data(), amounts.size()), offsets, data); + if (data.size() != req.outputs.size()) + { + MERROR("Unexpected output data size: expected " << req.outputs.size() << ", got " << data.size()); + return false; + } + for (const auto &t: data) + res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time), t.height, crypto::null_hash}); - res.outs.push_back({od.pubkey, od.commitment, unlocked, od.height, toi.first}); + if (req.get_txid) + { + for (size_t i = 0; i < req.outputs.size(); ++i) + { + tx_out_index toi = m_db->get_output_tx_and_index(req.outputs[i].amount, req.outputs[i].index); + res.outs[i].txid = toi.first; + } } } catch (const std::exception &e) @@ -1804,6 +1823,7 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, case STAGENET: start_height = stagenet_hard_forks[3].height; break; case TESTNET: start_height = testnet_hard_forks[3].height; break; case MAINNET: start_height = mainnet_hard_forks[3].height; break; + case FAKECHAIN: start_height = 0; break; default: return false; } } @@ -1822,18 +1842,21 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t db_height = m_db->height(); if (db_height == 0) return false; - if (to_height == 0) - to_height = db_height - 1; if (start_height >= db_height || to_height >= db_height) return false; if (amount == 0) { std::vector<uint64_t> heights; heights.reserve(to_height + 1 - start_height); - for (uint64_t h = start_height; h <= to_height; ++h) + uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height; + for (uint64_t h = real_start_height; h <= to_height; ++h) heights.push_back(h); distribution = m_db->get_block_cumulative_rct_outputs(heights); - base = 0; + if (start_height > 0) + { + base = distribution[0]; + distribution.erase(distribution.begin()); + } return true; } else @@ -3786,12 +3809,11 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) } //------------------------------------------------------------------ -//FIXME: unused parameter txs -void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, std::unordered_map<crypto::hash, cryptonote::transaction> &txs) const +void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs) const { try { - m_db->get_output_key(amount, offsets, outputs, true); + m_db->get_output_key(epee::span<const uint64_t>(&amount, 1), offsets, outputs, true); } catch (const std::exception& e) { @@ -4164,21 +4186,19 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete offsets.second.erase(last, offsets.second.end()); } - // [output] stores all transactions for each tx_out_index::hash found - std::vector<std::unordered_map<crypto::hash, cryptonote::transaction>> transactions(amounts.size()); - + // gather all the output keys threads = tpool.get_max_concurrency(); if (!m_db->can_thread_bulk_indices()) threads = 1; - if (threads > 1) + if (threads > 1 && amounts.size() > 1) { tools::threadpool::waiter waiter; for (size_t i = 0; i < amounts.size(); i++) { uint64_t amount = amounts[i]; - tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount]), std::ref(transactions[i])), true); + tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount])), true); } waiter.wait(&tpool); } @@ -4187,7 +4207,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete for (size_t i = 0; i < amounts.size(); i++) { uint64_t amount = amounts[i]; - output_scan_worker(amount, offset_map[amount], tx_map[amount], transactions[i]); + output_scan_worker(amount, offset_map[amount], tx_map[amount]); } } @@ -4254,9 +4274,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete return true; } -void Blockchain::add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta) +void Blockchain::add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta) { - m_db->add_txpool_tx(tx, meta); + m_db->add_txpool_tx(txid, blob, meta); } void Blockchain::update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta) diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index f140d7719..dfe833fb4 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -916,11 +916,9 @@ namespace cryptonote * @param amount the amount * @param offsets the indices (indexed to the amount) of the outputs * @param outputs return-by-reference the outputs collected - * @param txs unused, candidate for removal */ void output_scan_worker(const uint64_t amount,const std::vector<uint64_t> &offsets, - std::vector<output_data_t> &outputs, std::unordered_map<crypto::hash, - cryptonote::transaction> &txs) const; + std::vector<output_data_t> &outputs) const; /** * @brief computes the "short" and "long" hashes for a set of blocks @@ -939,7 +937,7 @@ namespace cryptonote */ std::list<std::pair<block_extended_info,std::vector<crypto::hash>>> get_alternative_chains() const; - void add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta); + void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta); void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta); void remove_txpool_tx(const crypto::hash &txid); uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 00537e8b7..b353cc5d1 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -906,7 +906,7 @@ namespace cryptonote } 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); + ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i], 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) @@ -1124,7 +1124,7 @@ namespace cryptonote blobdata bl; t_serializable_object_to_blob(tx, bl); 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); + return add_new_tx(tx, tx_hash, bl, tx_prefix_hash, tx_weight, tvc, keeped_by_block, relayed, do_not_relay); } //----------------------------------------------------------------------------------------------- size_t core::get_blockchain_total_transactions() const @@ -1132,7 +1132,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 tx_weight, 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 cryptonote::blobdata &blob, 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); @@ -1150,7 +1150,7 @@ namespace cryptonote } uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); - return m_mempool.add_tx(tx, tx_hash, tx_weight, tvc, keeped_by_block, relayed, do_not_relay, version); + return m_mempool.add_tx(tx, tx_hash, blob, 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 7ddba77b2..46c3c3e8b 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -782,13 +782,14 @@ namespace cryptonote * @copydoc add_new_tx(transaction&, tx_verification_context&, bool) * * @param tx_hash the transaction's hash + * @param blob the transaction as a blob * @param tx_prefix_hash the transaction prefix' hash * @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 tx_weight, 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 cryptonote::blobdata &blob, 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/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 70f7e8328..e2900916b 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -111,7 +111,7 @@ namespace cryptonote } //--------------------------------------------------------------------------------- - 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) + bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, 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); @@ -247,9 +247,11 @@ namespace cryptonote memset(meta.padding, 0, sizeof(meta.padding)); try { + if (kept_by_block) + m_parsed_tx_cache.insert(std::make_pair(id, tx)); CRITICAL_REGION_LOCAL1(m_blockchain); LockedTXN lock(m_blockchain); - m_blockchain.add_txpool_tx(tx, meta); + m_blockchain.add_txpool_tx(id, blob, meta); if (!insert_key_images(tx, id, kept_by_block)) return false; m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id); @@ -288,12 +290,13 @@ namespace cryptonote try { + if (kept_by_block) + m_parsed_tx_cache.insert(std::make_pair(id, tx)); CRITICAL_REGION_LOCAL1(m_blockchain); LockedTXN lock(m_blockchain); - const crypto::hash txid = get_transaction_hash(tx); - m_blockchain.remove_txpool_tx(txid); - m_blockchain.add_txpool_tx(tx, meta); - if (!insert_key_images(tx, txid, kept_by_block)) + m_blockchain.remove_txpool_tx(id); + m_blockchain.add_txpool_tx(id, blob, meta); + if (!insert_key_images(tx, id, kept_by_block)) return false; m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id); } @@ -324,9 +327,11 @@ namespace cryptonote { crypto::hash h = null_hash; size_t blob_size = 0; - if (!get_transaction_hash(tx, h, blob_size) || blob_size == 0) + cryptonote::blobdata bl; + t_serializable_object_to_blob(tx, bl); + if (bl.size() == 0 || !get_transaction_hash(tx, h)) return false; - return add_tx(tx, h, get_transaction_weight(tx, blob_size), tvc, keeped_by_block, relayed, do_not_relay, version); + return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, keeped_by_block, relayed, do_not_relay, version); } //--------------------------------------------------------------------------------- size_t tx_memory_pool::get_txpool_weight() const @@ -454,8 +459,6 @@ namespace cryptonote CRITICAL_REGION_LOCAL1(m_blockchain); auto sorted_it = find_tx_in_sorted_container(id); - if (sorted_it == m_txs_by_fee_and_receive_time.end()) - return false; try { @@ -467,7 +470,12 @@ namespace cryptonote return false; } cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(id); - if (!parse_and_validate_tx_from_blob(txblob, tx)) + auto ci = m_parsed_tx_cache.find(id); + if (ci != m_parsed_tx_cache.end()) + { + tx = ci->second; + } + else if (!parse_and_validate_tx_from_blob(txblob, tx)) { MERROR("Failed to parse tx from txpool"); return false; @@ -489,7 +497,8 @@ namespace cryptonote return false; } - m_txs_by_fee_and_receive_time.erase(sorted_it); + if (sorted_it != m_txs_by_fee_and_receive_time.end()) + m_txs_by_fee_and_receive_time.erase(sorted_it); ++m_cookie; return true; } @@ -910,6 +919,7 @@ namespace cryptonote { CRITICAL_REGION_LOCAL(m_transactions_lock); m_input_cache.clear(); + m_parsed_tx_cache.clear(); return true; } //--------------------------------------------------------------------------------- @@ -917,6 +927,7 @@ namespace cryptonote { CRITICAL_REGION_LOCAL(m_transactions_lock); m_input_cache.clear(); + m_parsed_tx_cache.clear(); return true; } //--------------------------------------------------------------------------------- diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 7a0cc23bf..670d70d77 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -107,7 +107,7 @@ namespace cryptonote * @param id the transaction's hash * @param tx_weight the transaction's weight */ - 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); + bool add_tx(transaction &tx, const crypto::hash &id, const cryptonote::blobdata &blob, 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 @@ -510,7 +510,7 @@ namespace cryptonote * @param txd the transaction to check (and info about it) * @param txid the txid of the transaction to check * @param txblob the transaction blob to check - * @param tx the parsed transaction prefix, if successful + * @param tx the parsed transaction, if successful * * @return true if the transaction is good to go, otherwise false */ @@ -584,6 +584,8 @@ private: size_t m_txpool_weight; mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache; + + std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache; }; } |