Add already_verified flag to add transaction operation of the txpool.

This is very useful when we are popping block, and txis are already
verified in that situation, which prevents verifying transactions again.
This commit is contained in:
0xFFFC0000 2024-02-02 00:24:23 +03:30
parent 059028a30a
commit 16d5206417
No known key found for this signature in database
GPG Key ID: 650F7C2B7BDA3819
4 changed files with 66 additions and 7 deletions

View File

@ -647,7 +647,7 @@ block Blockchain::pop_block_from_blockchain()
// that might not be always true. Unlikely though, and always relaying
// these again might cause a spike of traffic as many nodes re-relay
// all the transactions in a popped block when a reorg happens.
bool r = m_tx_pool.add_tx(tx, tvc, relay_method::block, true, version);
bool r = m_tx_pool.add_tx(tx, tvc, relay_method::block, true, version, true);
if (!r)
{
LOG_ERROR("Error returning transaction to tx_pool");
@ -3937,6 +3937,47 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time, uint8_t hf_versi
}
return false;
}
bool Blockchain::get_maximum_block_id_height(transaction& tx, uint8_t version, uint64_t* pmax_used_block_height, crypto::hash* pmax_used_block_id)
{
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
size_t sig_index = 0;
for (const auto& txin : tx.vin)
{
CHECK_AND_ASSERT_MES(txin.type() == typeid(txin_to_key), false, "wrong type id in tx input at Blockchain::check_tx_inputs");
const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx));
if (tx.version == 1)
{
// basically, make sure number of inputs == number of signatures
CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "wrong transaction: not signature entry for input with index= " << sig_index);
}
// make sure that output being spent matches up correctly with the
// signature spending it.
if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector<crypto::signature>(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height, version))
{
// MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index);
// if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain()
// {
// MERROR_VER(" *pmax_used_block_height: " << *pmax_used_block_height);
// }
return false;
}
sig_index++;
}
*pmax_used_block_id = m_db->get_block_hash_from_height(*pmax_used_block_height);
return true;
}
//------------------------------------------------------------------
// This function locates all outputs associated with a given input (mixins)
// and validates that they exist and are usable. It also checks the ring

View File

@ -31,6 +31,7 @@
#pragma once
#include <boost/asio/io_service.hpp>
#include <boost/function/function_fwd.hpp>
#include <cstdint>
#if BOOST_VERSION >= 107400
#include <boost/serialization/library_version_type.hpp>
#endif
@ -205,6 +206,16 @@ namespace cryptonote
*/
size_t get_alternative_blocks_count() const;
/**
* @brief get maximum used block height and id of transaction
*
* @param tx the transaction to get maximum input height
* @param version version of the hardfork
* @max_used_block_id return-by-reference block hash of most recent input
* @max_used_block_height return-by-reference return-by-reference block hash of most recent input
*/
bool get_maximum_block_id_height(transaction& tx, uint8_t version, uint64_t* pmax_used_block_height, crypto::hash* pmax_used_block_id);
/**
* @brief gets a block's hash given a height
*
@ -617,6 +628,7 @@ namespace cryptonote
*/
bool check_tx_inputs(transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false) const;
/**
* @brief get fee quantization mask
*

View File

@ -30,6 +30,7 @@
#include <algorithm>
#include <boost/filesystem.hpp>
#include <cstdint>
#include <unordered_set>
#include <vector>
@ -140,7 +141,7 @@ 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, bool already_verified)
{
const bool kept_by_block = (tx_relay == relay_method::block);
@ -265,8 +266,13 @@ namespace cryptonote
crypto::hash max_used_block_id = null_hash;
uint64_t max_used_block_height = 0;
if(already_verified) {
m_blockchain.get_maximum_block_id_height(tx, version, &max_used_block_height, &max_used_block_id);
}
cryptonote::txpool_tx_meta_t meta{};
bool ch_inp_res = check_tx_inputs([&tx]()->cryptonote::transaction&{ return tx; }, id, max_used_block_height, max_used_block_id, tvc, kept_by_block);
bool ch_inp_res = already_verified ? true : check_tx_inputs([&tx]()->cryptonote::transaction&{ return tx; }, id, max_used_block_height, max_used_block_id, tvc, kept_by_block);
if(!ch_inp_res)
{
// if the transaction was valid before (kept_by_block), then it
@ -396,14 +402,14 @@ 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, bool already_verified)
{
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, already_verified);
}
//---------------------------------------------------------------------------------
size_t tx_memory_pool::get_txpool_weight() const

View File

@ -104,7 +104,7 @@ namespace cryptonote
* @tx_relay how the transaction was received
* @param tx_weight the transaction's weight
*/
bool add_tx(transaction &tx, 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 add_tx(transaction &tx, 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 already_verified = false);
/**
* @brief add a transaction to the transaction pool
@ -122,7 +122,7 @@ namespace cryptonote
*
* @return true if the transaction passes validations, otherwise false
*/
bool add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version);
bool add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version, bool already_verified = false);
/**
* @brief takes a transaction with the given hash from the pool