aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core/tx_pool.cpp
diff options
context:
space:
mode:
authortobtoht <tob@featherwallet.org>2025-03-10 16:20:00 +0000
committertobtoht <tob@featherwallet.org>2025-03-10 16:20:00 +0000
commit3da68db9789697d30dc309df2f1da5d348bc4ce2 (patch)
tree68c98fab9146797007ab778cdb4a609e1e41f43c /src/cryptonote_core/tx_pool.cpp
parent0232839913b13cf0ab0bb7ad25fff0c05f37d2fe (diff)
parent008ba966da88f073f226b299533faca905ceabf8 (diff)
downloadmonzero-core-3da68db9789697d30dc309df2f1da5d348bc4ce2.tar.gz
monzero-core-3da68db9789697d30dc309df2f1da5d348bc4ce2.tar.xz
monzero-core-3da68db9789697d30dc309df2f1da5d348bc4ce2.zip
Merge pull request #9740
008ba966d blockchain sync: reduce disk writes from 2 to 1 per tx (jeffro256)
Diffstat (limited to 'src/cryptonote_core/tx_pool.cpp')
-rw-r--r--src/cryptonote_core/tx_pool.cpp150
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;
}