diff options
| author | jeffro256 <jeffro256@tutanota.com> | 2024-01-17 17:17:16 -0600 |
|---|---|---|
| committer | jeffro256 <jeffro256@tutanota.com> | 2025-03-10 01:32:08 -0500 |
| commit | 008ba966da88f073f226b299533faca905ceabf8 (patch) | |
| tree | 1be6c2f8d45b74ad0427e0117c67371c93974f7e /src/cryptonote_core/tx_pool.cpp | |
| parent | d0118f4778db7e75d7ad2036076e5688cd6f3810 (diff) | |
| download | monzero-core-008ba966da88f073f226b299533faca905ceabf8.tar.gz monzero-core-008ba966da88f073f226b299533faca905ceabf8.tar.xz monzero-core-008ba966da88f073f226b299533faca905ceabf8.zip | |
blockchain sync: reduce disk writes from 2 to 1 per tx
Diffstat (limited to 'src/cryptonote_core/tx_pool.cpp')
| -rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 150 |
1 files changed, 40 insertions, 110 deletions
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 0af6cab85..b44fcbe28 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -36,6 +36,7 @@ #include "tx_pool.h" #include "cryptonote_tx_utils.h" #include "cryptonote_basic/cryptonote_boost_serialization.h" +#include "cryptonote_basic/events.h" #include "cryptonote_config.h" #include "blockchain.h" #include "blockchain_db/locked_txn.h" @@ -43,6 +44,8 @@ #include "common/boost_serialization_helper.h" #include "int-util.h" #include "misc_language.h" +#include "misc_log_ex.h" +#include "tx_verification_utils.h" #include "warnings.h" #include "common/perf_timer.h" #include "crypto/hash.h" @@ -110,15 +113,6 @@ namespace cryptonote return amount * ACCEPT_THRESHOLD; } - uint64_t get_transaction_weight_limit(uint8_t version) - { - // from v8, limit a tx to 50% of the minimum block weight - if (version >= 8) - return get_min_block_weight(version) / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; - else - return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; - } - // external lock must be held for the comparison+set to work properly void set_if_less(std::atomic<time_t>& next_check, const time_t candidate) noexcept { @@ -141,7 +135,10 @@ namespace cryptonote // corresponding lists. } //--------------------------------------------------------------------------------- - 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, relay_method tx_relay, bool relayed, 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, relay_method tx_relay, bool relayed, + uint8_t version, uint8_t nic_verified_hf_version) { const bool kept_by_block = (tx_relay == relay_method::block); @@ -149,13 +146,6 @@ namespace cryptonote CRITICAL_REGION_LOCAL(m_transactions_lock); PERF_TIMER(add_tx); - if (tx.version == 0) - { - // v0 never accepted - LOG_PRINT_L1("transaction version 0 is invalid"); - tvc.m_verifivation_failed = true; - return false; - } // we do not accept transactions that timed out before, unless they're // kept_by_block @@ -167,49 +157,24 @@ namespace cryptonote return false; } - if(!check_inputs_types_supported(tx)) + if (version != nic_verified_hf_version && !cryptonote::ver_non_input_consensus(tx, tvc, version)) { - tvc.m_verifivation_failed = true; - tvc.m_invalid_input = true; + LOG_PRINT_L1("transaction " << id << " failed non-input consensus rule checks"); + tvc.m_verifivation_failed = true; // should already be set, but just in case return false; } - // fee per kilobyte, size rounded up. uint64_t fee; - - if (tx.version == 1) - { - uint64_t inputs_amount = 0; - if(!get_inputs_money_amount(tx, inputs_amount)) - { - tvc.m_verifivation_failed = true; - return false; - } - - uint64_t outputs_amount = get_outs_money_amount(tx); - if(outputs_amount > inputs_amount) - { - LOG_PRINT_L1("transaction use more money than it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount)); - tvc.m_verifivation_failed = true; - tvc.m_overspend = true; - return false; - } - else if(outputs_amount == inputs_amount) - { - LOG_PRINT_L1("transaction fee is zero: outputs_amount == inputs_amount, rejecting."); - tvc.m_verifivation_failed = true; - tvc.m_fee_too_low = true; - return false; - } - - fee = inputs_amount - outputs_amount; - } - else + bool fee_good = false; + try { - fee = tx.rct_signatures.txnFee; + // get_tx_fee() can throw. It shouldn't throw because we check preconditions in + // ver_non_input_consensus(), but let's put it in a try block just in case. + fee = get_tx_fee(tx); + fee_good = kept_by_block || m_blockchain.check_fee(tx_weight, fee); } - - if (!kept_by_block && !m_blockchain.check_fee(tx_weight, fee)) + catch(...) {} + if (!fee_good) // if fee calculation failed or fee in relayed tx is too low... { tvc.m_verifivation_failed = true; tvc.m_fee_too_low = true; @@ -217,15 +182,6 @@ namespace cryptonote return false; } - size_t tx_weight_limit = get_transaction_weight_limit(version); - if ((!kept_by_block || version >= HF_VERSION_PER_BYTE_FEE) && tx_weight > tx_weight_limit) - { - LOG_PRINT_L1("transaction is too heavy: " << tx_weight << " bytes, maximum weight: " << tx_weight_limit); - tvc.m_verifivation_failed = true; - tvc.m_too_big = true; - return false; - } - size_t tx_extra_size = tx.extra.size(); if (!kept_by_block && tx_extra_size > MAX_TX_EXTRA_SIZE) { @@ -261,14 +217,6 @@ namespace cryptonote } } - if (!m_blockchain.check_tx_outputs(tx, tvc)) - { - LOG_PRINT_L1("Transaction with id= "<< id << " has at least one invalid output"); - tvc.m_verifivation_failed = true; - tvc.m_invalid_output = true; - return false; - } - // assume failure during verification steps until success is certain tvc.m_verifivation_failed = true; @@ -382,13 +330,13 @@ namespace cryptonote add_tx_to_transient_lists(id, meta.fee / (double)(tx_weight ? tx_weight : 1), receive_time); } lock.commit(); + tvc.m_added_to_pool = !existing_tx; } catch (const std::exception &e) { MERROR("internal error: error adding transaction to txpool: " << e.what()); return false; } - tvc.m_added_to_pool = true; static_assert(unsigned(relay_method::none) == 0, "expected relay_method::none value to be zero"); if(meta.fee > 0 && tx_relay != relay_method::forward) @@ -407,14 +355,16 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- - bool tx_memory_pool::add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version) + bool tx_memory_pool::add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, + bool relayed, uint8_t version, uint8_t nic_verified_hf_version) { crypto::hash h = null_hash; 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, bl, get_transaction_weight(tx, bl.size()), tvc, tx_relay, relayed, version); + return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, tx_relay, relayed, version, + nic_verified_hf_version); } //--------------------------------------------------------------------------------- size_t tx_memory_pool::get_txpool_weight() const @@ -580,7 +530,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- - bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen, bool &pruned) + bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen, bool &pruned, const bool suppress_missing_msgs) { CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL1(m_blockchain); @@ -592,7 +542,10 @@ namespace cryptonote txpool_tx_meta_t meta; if (!m_blockchain.get_txpool_tx_meta(id, meta)) { - MERROR("Failed to find tx_meta in txpool"); + if (!suppress_missing_msgs) + { + MERROR("Failed to find tx_meta in txpool"); + } return false; } txblob = m_blockchain.get_txpool_tx_blob(id, relay_category::all); @@ -1466,44 +1419,21 @@ namespace cryptonote bool parsed; } lazy_tx(txblob, txid, tx); - //not the best implementation at this time, sorry :( - //check is ring_signature already checked ? - if(txd.max_used_block_id == null_hash) - {//not checked, lets try to check + const std::uint64_t top_block_height{m_blockchain.get_current_blockchain_height() - 1}; + const crypto::hash top_block_hash{m_blockchain.get_block_id_by_height(top_block_height)}; - if(txd.last_failed_id != null_hash && m_blockchain.get_current_blockchain_height() > txd.last_failed_height && txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) - return false;//we already sure that this tx is broken for this height + if (txd.last_failed_id == top_block_hash) + return false; // we are already sure that this tx isn't passing for this exact chain - tx_verification_context tvc; - if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc)) - { - txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1; - txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); - return false; - } - }else - { - if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height()) - return false; - if(true) - { - //if we already failed on this height and id, skip actual ring signature check - if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) - return false; - //check ring signature again, it is possible (with very small chance) that this transaction become again valid - tx_verification_context tvc; - if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc)) - { - txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1; - txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); - return false; - } - } - } - //if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure - if(m_blockchain.have_tx_keyimges_as_spent(lazy_tx())) + tx_verification_context tvc{}; + if (!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, + txid, + txd.max_used_block_height, + txd.max_used_block_id, + tvc)) { - txd.double_spend_seen = true; + txd.last_failed_height = top_block_height; + txd.last_failed_id = top_block_hash; return false; } |
