mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-22 15:32:24 +00:00
Adding support for hidden (anonymity) txpool
This commit is contained in:
parent
3e3db92303
commit
5d7ae2d279
35 changed files with 1372 additions and 316 deletions
|
@ -110,7 +110,8 @@ namespace epee
|
|||
constexpr std::size_t size() const noexcept { return len; }
|
||||
constexpr std::size_t size_bytes() const noexcept { return size() * sizeof(value_type); }
|
||||
|
||||
const T &operator[](size_t idx) const { return ptr[idx]; }
|
||||
T &operator[](size_t idx) noexcept { return ptr[idx]; }
|
||||
const T &operator[](size_t idx) const noexcept { return ptr[idx]; }
|
||||
|
||||
private:
|
||||
T* ptr;
|
||||
|
|
|
@ -44,6 +44,71 @@ using epee::string_tools::pod_to_hex;
|
|||
namespace cryptonote
|
||||
{
|
||||
|
||||
bool matches_category(relay_method method, relay_category category) noexcept
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
case relay_category::all:
|
||||
return true;
|
||||
case relay_category::relayable:
|
||||
if (method == relay_method::none)
|
||||
return false;
|
||||
return true;
|
||||
case relay_category::broadcasted:
|
||||
case relay_category::legacy:
|
||||
break;
|
||||
}
|
||||
// check for "broadcasted" or "legacy" methods:
|
||||
switch (method)
|
||||
{
|
||||
default:
|
||||
case relay_method::local:
|
||||
return false;
|
||||
case relay_method::block:
|
||||
case relay_method::flood:
|
||||
return true;
|
||||
case relay_method::none:
|
||||
break;
|
||||
}
|
||||
return category == relay_category::legacy;
|
||||
}
|
||||
|
||||
void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept
|
||||
{
|
||||
kept_by_block = 0;
|
||||
do_not_relay = 0;
|
||||
is_local = 0;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case relay_method::none:
|
||||
do_not_relay = 1;
|
||||
break;
|
||||
case relay_method::local:
|
||||
is_local = 1;
|
||||
break;
|
||||
default:
|
||||
case relay_method::flood:
|
||||
break;
|
||||
case relay_method::block:
|
||||
kept_by_block = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
relay_method txpool_tx_meta_t::get_relay_method() const noexcept
|
||||
{
|
||||
if (kept_by_block)
|
||||
return relay_method::block;
|
||||
if (do_not_relay)
|
||||
return relay_method::none;
|
||||
if (is_local)
|
||||
return relay_method::local;
|
||||
return relay_method::flood;
|
||||
}
|
||||
|
||||
const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
|
||||
"db-sync-mode"
|
||||
, "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[<nblocks_per_sync>[blocks]|<nbytes_per_sync>[bytes]]."
|
||||
|
@ -924,4 +989,23 @@ void BlockchainDB::fixup()
|
|||
batch_stop();
|
||||
}
|
||||
|
||||
bool BlockchainDB::txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category)
|
||||
{
|
||||
try
|
||||
{
|
||||
txpool_tx_meta_t meta{};
|
||||
if (!get_txpool_tx_meta(tx_hash, meta))
|
||||
{
|
||||
MERROR("Failed to get tx meta from txpool");
|
||||
return false;
|
||||
}
|
||||
return meta.matches(category);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MERROR("Failed to get tx meta from txpool: " << e.what());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cryptonote
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/difficulty.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
|
||||
/** \file
|
||||
* Cryptonote Blockchain Database Interface
|
||||
|
@ -105,6 +106,16 @@ typedef std::pair<crypto::hash, uint64_t> tx_out_index;
|
|||
extern const command_line::arg_descriptor<std::string> arg_db_sync_mode;
|
||||
extern const command_line::arg_descriptor<bool, false> arg_db_salvage;
|
||||
|
||||
enum class relay_category : uint8_t
|
||||
{
|
||||
broadcasted = 0,//!< Public txes received via block/flooding/fluff
|
||||
relayable, //!< Every tx not marked `relay_method::none`
|
||||
legacy, //!< `relay_category::broadcasted` + `relay_method::none` for rpc relay requests or historical reasons
|
||||
all //!< Everything in the db
|
||||
};
|
||||
|
||||
bool matches_category(relay_method method, relay_category category) noexcept;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
|
@ -156,11 +167,22 @@ struct txpool_tx_meta_t
|
|||
uint8_t do_not_relay;
|
||||
uint8_t double_spend_seen: 1;
|
||||
uint8_t pruned: 1;
|
||||
uint8_t bf_padding: 6;
|
||||
uint8_t is_local: 1;
|
||||
uint8_t bf_padding: 5;
|
||||
|
||||
uint8_t padding[76]; // till 192 bytes
|
||||
|
||||
void set_relay_method(relay_method method) noexcept;
|
||||
relay_method get_relay_method() const noexcept;
|
||||
|
||||
//! See `relay_category` description
|
||||
bool matches(const relay_category category) const noexcept
|
||||
{
|
||||
return matches_category(get_relay_method(), category);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define DBF_SAFE 1
|
||||
#define DBF_FAST 2
|
||||
#define DBF_FASTEST 4
|
||||
|
@ -1465,12 +1487,12 @@ public:
|
|||
/**
|
||||
* @brief get the number of transactions in the txpool
|
||||
*/
|
||||
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const = 0;
|
||||
virtual uint64_t get_txpool_tx_count(relay_category tx_category = relay_category::broadcasted) const = 0;
|
||||
|
||||
/**
|
||||
* @brief check whether a txid is in the txpool
|
||||
* @brief check whether a txid is in the txpool and meets tx_category requirements
|
||||
*/
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid) const = 0;
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid, relay_category tx_category) const = 0;
|
||||
|
||||
/**
|
||||
* @brief remove a txpool transaction
|
||||
|
@ -1494,10 +1516,11 @@ public:
|
|||
*
|
||||
* @param txid the transaction id of the transation to lookup
|
||||
* @param bd the blob to return
|
||||
* @param tx_category for filtering out hidden/private txes
|
||||
*
|
||||
* @return true if the txid was in the txpool, false otherwise
|
||||
* @return True iff `txid` is in the pool and meets `tx_category` requirements
|
||||
*/
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const = 0;
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const = 0;
|
||||
|
||||
/**
|
||||
* @brief get a txpool transaction's blob
|
||||
|
@ -1506,7 +1529,17 @@ public:
|
|||
*
|
||||
* @return the blob for that transaction
|
||||
*/
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const = 0;
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if `tx_hash` relay status is in `category`.
|
||||
*
|
||||
* @param tx_hash hash of the transaction to lookup
|
||||
* @param category relay status category to test against
|
||||
*
|
||||
* @return True if `tx_hash` latest relay status is in `category`.
|
||||
*/
|
||||
bool txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category);
|
||||
|
||||
/**
|
||||
* @brief prune output data for the given amount
|
||||
|
@ -1604,7 +1637,7 @@ public:
|
|||
*
|
||||
* @return false if the function returns false for any transaction, otherwise true
|
||||
*/
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = true) const = 0;
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const = 0;
|
||||
|
||||
/**
|
||||
* @brief runs a function over all key images stored
|
||||
|
|
|
@ -1771,7 +1771,7 @@ void BlockchainLMDB::update_txpool_tx(const crypto::hash &txid, const txpool_tx_
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const
|
||||
uint64_t BlockchainLMDB::get_txpool_tx_count(relay_category category) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
@ -1781,7 +1781,7 @@ uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const
|
|||
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
if (include_unrelayed_txes)
|
||||
if (category == relay_category::all)
|
||||
{
|
||||
// No filtering, we can get the number of tx the "fast" way
|
||||
MDB_stat db_stats;
|
||||
|
@ -1807,7 +1807,7 @@ uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const
|
|||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate txpool tx metadata: ", result).c_str()));
|
||||
const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data;
|
||||
if (!meta.do_not_relay)
|
||||
if (meta.matches(category))
|
||||
++num_entries;
|
||||
}
|
||||
}
|
||||
|
@ -1816,7 +1816,7 @@ uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const
|
|||
return num_entries;
|
||||
}
|
||||
|
||||
bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const
|
||||
bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid, relay_category tx_category) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
@ -1825,11 +1825,21 @@ bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const
|
|||
RCURSOR(txpool_meta)
|
||||
|
||||
MDB_val k = {sizeof(txid), (void *)&txid};
|
||||
auto result = mdb_cursor_get(m_cur_txpool_meta, &k, NULL, MDB_SET);
|
||||
MDB_val v;
|
||||
auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET);
|
||||
if (result != 0 && result != MDB_NOTFOUND)
|
||||
throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
|
||||
if (result == MDB_NOTFOUND)
|
||||
return false;
|
||||
|
||||
bool found = true;
|
||||
if (tx_category != relay_category::all)
|
||||
{
|
||||
const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data;
|
||||
found = meta.matches(tx_category);
|
||||
}
|
||||
TXN_POSTFIX_RDONLY();
|
||||
return result != MDB_NOTFOUND;
|
||||
return found;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::remove_txpool_tx(const crypto::hash& txid)
|
||||
|
@ -1883,7 +1893,7 @@ bool BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
|
||||
bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
@ -1893,6 +1903,21 @@ bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::bl
|
|||
|
||||
MDB_val k = {sizeof(txid), (void *)&txid};
|
||||
MDB_val v;
|
||||
|
||||
// if filtering, make sure those requirements are met before copying blob
|
||||
if (tx_category != relay_category::all)
|
||||
{
|
||||
auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET);
|
||||
if (result == MDB_NOTFOUND)
|
||||
return false;
|
||||
if (result != 0)
|
||||
throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
|
||||
|
||||
const txpool_tx_meta_t& meta = *(const txpool_tx_meta_t*)v.mv_data;
|
||||
if (!meta.matches(tx_category))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = mdb_cursor_get(m_cur_txpool_blob, &k, &v, MDB_SET);
|
||||
if (result == MDB_NOTFOUND)
|
||||
return false;
|
||||
|
@ -1904,10 +1929,10 @@ bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::bl
|
|||
return true;
|
||||
}
|
||||
|
||||
cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const
|
||||
cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const
|
||||
{
|
||||
cryptonote::blobdata bd;
|
||||
if (!get_txpool_tx_blob(txid, bd))
|
||||
if (!get_txpool_tx_blob(txid, bd, tx_category))
|
||||
throw1(DB_ERROR("Tx not found in txpool: "));
|
||||
return bd;
|
||||
}
|
||||
|
@ -2245,7 +2270,7 @@ bool BlockchainLMDB::check_pruning()
|
|||
return prune_worker(prune_mode_check, 0);
|
||||
}
|
||||
|
||||
bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, bool include_unrelayed_txes) const
|
||||
bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, relay_category category) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
@ -2269,8 +2294,7 @@ bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&,
|
|||
throw0(DB_ERROR(lmdb_error("Failed to enumerate txpool tx metadata: ", result).c_str()));
|
||||
const crypto::hash txid = *(const crypto::hash*)k.mv_data;
|
||||
const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data;
|
||||
if (!include_unrelayed_txes && meta.do_not_relay)
|
||||
// Skipping that tx
|
||||
if (!meta.matches(category))
|
||||
continue;
|
||||
const cryptonote::blobdata *passed_bd = NULL;
|
||||
cryptonote::blobdata bd;
|
||||
|
|
|
@ -281,12 +281,12 @@ public:
|
|||
|
||||
virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t& meta);
|
||||
virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& meta);
|
||||
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const;
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid) const;
|
||||
virtual uint64_t get_txpool_tx_count(relay_category category = relay_category::broadcasted) const;
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid, relay_category tx_category) const;
|
||||
virtual void remove_txpool_tx(const crypto::hash& txid);
|
||||
virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const;
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata& bd, relay_category tx_category) const;
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const;
|
||||
virtual uint32_t get_blockchain_pruning_seed() const;
|
||||
virtual bool prune_blockchain(uint32_t pruning_seed = 0);
|
||||
virtual bool update_pruning();
|
||||
|
@ -298,7 +298,7 @@ public:
|
|||
virtual uint64_t get_alt_block_count();
|
||||
virtual void drop_alt_blocks();
|
||||
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const;
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, relay_category category = relay_category::broadcasted) const;
|
||||
|
||||
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
|
||||
virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const;
|
||||
|
|
|
@ -126,14 +126,14 @@ public:
|
|||
|
||||
virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const cryptonote::txpool_tx_meta_t& details) override {}
|
||||
virtual void update_txpool_tx(const crypto::hash &txid, const cryptonote::txpool_tx_meta_t& details) override {}
|
||||
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const override { return 0; }
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid) const override { return false; }
|
||||
virtual uint64_t get_txpool_tx_count(relay_category tx_relay = relay_category::broadcasted) const override { return 0; }
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid, relay_category tx_category) const override { return false; }
|
||||
virtual void remove_txpool_tx(const crypto::hash& txid) override {}
|
||||
virtual bool get_txpool_tx_meta(const crypto::hash& txid, cryptonote::txpool_tx_meta_t &meta) const override { return false; }
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const override { return false; }
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const override { return false; }
|
||||
virtual uint64_t get_database_size() const override { return 0; }
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const override { return ""; }
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const override { return false; }
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const override { return ""; }
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const override { return false; }
|
||||
|
||||
virtual void add_block( const cryptonote::block& blk
|
||||
, size_t block_weight
|
||||
|
|
|
@ -174,7 +174,7 @@ int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &block
|
|||
for(auto& tx_blob: block_entry.txs)
|
||||
{
|
||||
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
core.handle_incoming_tx(tx_blob, tvc, true, true, false);
|
||||
core.handle_incoming_tx(tx_blob, tvc, relay_method::block, true);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{
|
||||
MERROR("transaction verification failed, tx_id = "
|
||||
|
|
|
@ -616,7 +616,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, true, true, false, version);
|
||||
bool r = m_tx_pool.add_tx(tx, tvc, relay_method::block, true, version);
|
||||
if (!r)
|
||||
{
|
||||
LOG_ERROR("Error returning transaction to tx_pool");
|
||||
|
@ -1765,7 +1765,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
|
|||
{
|
||||
cryptonote::tx_memory_pool::tx_details td;
|
||||
cryptonote::blobdata blob;
|
||||
if (m_tx_pool.have_tx(txid))
|
||||
if (m_tx_pool.have_tx(txid, relay_category::legacy))
|
||||
{
|
||||
if (m_tx_pool.get_transaction_info(txid, td))
|
||||
{
|
||||
|
@ -3641,7 +3641,7 @@ void Blockchain::return_tx_to_pool(std::vector<std::pair<transaction, blobdata>>
|
|||
// all the transactions in a popped block when a reorg happens.
|
||||
const size_t weight = get_transaction_weight(tx.first, tx.second.size());
|
||||
const crypto::hash tx_hash = get_transaction_hash(tx.first);
|
||||
if (!m_tx_pool.add_tx(tx.first, tx_hash, tx.second, weight, tvc, true, true, false, version))
|
||||
if (!m_tx_pool.add_tx(tx.first, tx_hash, tx.second, weight, tvc, relay_method::block, true, version))
|
||||
{
|
||||
MERROR("Failed to return taken transaction with hash: " << get_transaction_hash(tx.first) << " to tx_pool");
|
||||
}
|
||||
|
@ -3661,7 +3661,7 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
|
|||
uint64_t fee;
|
||||
bool relayed, do_not_relay, double_spend_seen, pruned;
|
||||
MINFO("Removing txid " << txid << " from the pool");
|
||||
if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, pruned))
|
||||
if(!m_tx_pool.have_tx(txid, relay_category::all) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, pruned))
|
||||
{
|
||||
MERROR("Failed to remove txid " << txid << " from the pool");
|
||||
res = false;
|
||||
|
@ -4895,9 +4895,9 @@ void Blockchain::remove_txpool_tx(const crypto::hash &txid)
|
|||
m_db->remove_txpool_tx(txid);
|
||||
}
|
||||
|
||||
uint64_t Blockchain::get_txpool_tx_count(bool include_unrelayed_txes) const
|
||||
uint64_t Blockchain::get_txpool_tx_count(bool include_sensitive) const
|
||||
{
|
||||
return m_db->get_txpool_tx_count(include_unrelayed_txes);
|
||||
return m_db->get_txpool_tx_count(include_sensitive ? relay_category::all : relay_category::broadcasted);
|
||||
}
|
||||
|
||||
bool Blockchain::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const
|
||||
|
@ -4905,19 +4905,24 @@ bool Blockchain::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &
|
|||
return m_db->get_txpool_tx_meta(txid, meta);
|
||||
}
|
||||
|
||||
bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
|
||||
bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const
|
||||
{
|
||||
return m_db->get_txpool_tx_blob(txid, bd);
|
||||
return m_db->get_txpool_tx_blob(txid, bd, tx_category);
|
||||
}
|
||||
|
||||
cryptonote::blobdata Blockchain::get_txpool_tx_blob(const crypto::hash& txid) const
|
||||
cryptonote::blobdata Blockchain::get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const
|
||||
{
|
||||
return m_db->get_txpool_tx_blob(txid);
|
||||
return m_db->get_txpool_tx_blob(txid, tx_category);
|
||||
}
|
||||
|
||||
bool Blockchain::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, bool include_unrelayed_txes) const
|
||||
bool Blockchain::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, relay_category tx_category) const
|
||||
{
|
||||
return m_db->for_all_txpool_txes(f, include_blob, include_unrelayed_txes);
|
||||
return m_db->for_all_txpool_txes(f, include_blob, tx_category);
|
||||
}
|
||||
|
||||
bool Blockchain::txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category)
|
||||
{
|
||||
return m_db->txpool_tx_matches_category(tx_hash, category);
|
||||
}
|
||||
|
||||
void Blockchain::set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync)
|
||||
|
@ -5098,7 +5103,7 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
|
|||
CRITICAL_REGION_LOCAL(m_tx_pool);
|
||||
|
||||
std::vector<transaction> txs;
|
||||
m_tx_pool.get_transactions(txs);
|
||||
m_tx_pool.get_transactions(txs, true);
|
||||
|
||||
size_t tx_weight;
|
||||
uint64_t fee;
|
||||
|
|
|
@ -964,11 +964,12 @@ namespace cryptonote
|
|||
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;
|
||||
uint64_t get_txpool_tx_count(bool include_sensitive = false) const;
|
||||
bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const;
|
||||
bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
|
||||
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
|
||||
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = true) const;
|
||||
bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const;
|
||||
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const;
|
||||
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, relay_category tx_category = relay_category::broadcasted) const;
|
||||
bool txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category);
|
||||
|
||||
bool is_within_compiled_block_hash_area() const { return is_within_compiled_block_hash_area(m_db->height()); }
|
||||
uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes, const std::vector<uint64_t> &weights);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/uuid/nil_generator.hpp>
|
||||
|
||||
#include "string_tools.h"
|
||||
using namespace epee;
|
||||
|
@ -753,7 +754,7 @@ namespace cryptonote
|
|||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
bool core::handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash)
|
||||
{
|
||||
tvc = {};
|
||||
|
||||
|
@ -817,7 +818,7 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx_post(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
bool core::handle_incoming_tx_post(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash)
|
||||
{
|
||||
if(!check_tx_syntax(tx))
|
||||
{
|
||||
|
@ -946,23 +947,29 @@ namespace cryptonote
|
|||
return ret;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
bool core::handle_incoming_txs(const epee::span<const tx_blob_entry> tx_blobs, epee::span<tx_verification_context> tvc, relay_method tx_relay, bool relayed)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
|
||||
|
||||
if (tx_blobs.size() != tvc.size())
|
||||
{
|
||||
MERROR("tx_blobs and tx_verification_context spans must have equal size");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; };
|
||||
std::vector<result> results(tx_blobs.size());
|
||||
|
||||
tvc.resize(tx_blobs.size());
|
||||
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
|
||||
|
||||
tools::threadpool& tpool = tools::threadpool::getInstance();
|
||||
tools::threadpool::waiter waiter;
|
||||
std::vector<tx_blob_entry>::const_iterator it = tx_blobs.begin();
|
||||
epee::span<tx_blob_entry>::const_iterator it = tx_blobs.begin();
|
||||
for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
|
||||
tpool.submit(&waiter, [&, i, it] {
|
||||
try
|
||||
{
|
||||
results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash, keeped_by_block, relayed, do_not_relay);
|
||||
results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
@ -978,7 +985,7 @@ namespace cryptonote
|
|||
for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
|
||||
if (!results[i].res)
|
||||
continue;
|
||||
if(m_mempool.have_tx(results[i].hash))
|
||||
if(m_mempool.have_tx(results[i].hash, relay_category::legacy))
|
||||
{
|
||||
LOG_PRINT_L2("tx " << results[i].hash << "already have transaction in tx_pool");
|
||||
already_have[i] = true;
|
||||
|
@ -993,7 +1000,7 @@ namespace cryptonote
|
|||
tpool.submit(&waiter, [&, i, it] {
|
||||
try
|
||||
{
|
||||
results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash, keeped_by_block, relayed, do_not_relay);
|
||||
results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
@ -1014,7 +1021,7 @@ namespace cryptonote
|
|||
tx_info.push_back({&results[i].tx, results[i].hash, tvc[i], results[i].res});
|
||||
}
|
||||
if (!tx_info.empty())
|
||||
handle_incoming_tx_accumulated_batch(tx_info, keeped_by_block);
|
||||
handle_incoming_tx_accumulated_batch(tx_info, tx_relay == relay_method::block);
|
||||
|
||||
bool ok = true;
|
||||
it = tx_blobs.begin();
|
||||
|
@ -1024,13 +1031,14 @@ namespace cryptonote
|
|||
ok = false;
|
||||
continue;
|
||||
}
|
||||
if (keeped_by_block)
|
||||
if (tx_relay == relay_method::block)
|
||||
get_blockchain_storage().on_new_tx_from_block(results[i].tx);
|
||||
if (already_have[i])
|
||||
continue;
|
||||
|
||||
const uint64_t weight = results[i].tx.pruned ? get_pruned_transaction_weight(results[i].tx) : get_transaction_weight(results[i].tx, it->blob.size());
|
||||
ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i].blob, weight, tvc[i], keeped_by_block, relayed, do_not_relay);
|
||||
ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i].blob, weight, tvc[i], tx_relay, relayed);
|
||||
|
||||
if(tvc[i].m_verifivation_failed)
|
||||
{MERROR_VER("Transaction verification failed: " << results[i].hash);}
|
||||
else if(tvc[i].m_verifivation_impossible)
|
||||
|
@ -1044,19 +1052,9 @@ namespace cryptonote
|
|||
CATCH_ENTRY_L0("core::handle_incoming_txs()", false);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
bool core::handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, relay_method tx_relay, bool relayed)
|
||||
{
|
||||
std::vector<tx_blob_entry> tx_blobs;
|
||||
tx_blobs.push_back(tx_blob);
|
||||
std::vector<tx_verification_context> tvcv(1);
|
||||
bool r = handle_incoming_txs(tx_blobs, tvcv, keeped_by_block, relayed, do_not_relay);
|
||||
tvc = tvcv[0];
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
{
|
||||
return handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, keeped_by_block, relayed, do_not_relay);
|
||||
return handle_incoming_txs({std::addressof(tx_blob), 1}, {std::addressof(tvc), 1}, tx_relay, relayed);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_stat_info(core_stat_info& st_inf) const
|
||||
|
@ -1246,13 +1244,13 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
bool core::add_new_tx(transaction& tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed)
|
||||
{
|
||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
||||
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, bl, tx_weight, tvc, keeped_by_block, relayed, do_not_relay);
|
||||
return add_new_tx(tx, tx_hash, bl, tx_weight, tvc, tx_relay, relayed);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t core::get_blockchain_total_transactions() const
|
||||
|
@ -1260,9 +1258,9 @@ namespace cryptonote
|
|||
return m_blockchain_storage.get_total_transactions();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, 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, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed)
|
||||
{
|
||||
if(m_mempool.have_tx(tx_hash))
|
||||
if(m_mempool.have_tx(tx_hash, relay_category::legacy))
|
||||
{
|
||||
LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
|
||||
return true;
|
||||
|
@ -1275,40 +1273,62 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
return m_mempool.add_tx(tx, tx_hash, blob, tx_weight, tvc, keeped_by_block, relayed, do_not_relay, version);
|
||||
return m_mempool.add_tx(tx, tx_hash, blob, tx_weight, tvc, tx_relay, relayed, version);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::relay_txpool_transactions()
|
||||
{
|
||||
// we attempt to relay txes that should be relayed, but were not
|
||||
std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
|
||||
std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> txs;
|
||||
if (m_mempool.get_relayable_transactions(txs) && !txs.empty())
|
||||
{
|
||||
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
|
||||
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
NOTIFY_NEW_TRANSACTIONS::request r;
|
||||
for (auto it = txs.begin(); it != txs.end(); ++it)
|
||||
NOTIFY_NEW_TRANSACTIONS::request public_req{};
|
||||
NOTIFY_NEW_TRANSACTIONS::request private_req{};
|
||||
for (auto& tx : txs)
|
||||
{
|
||||
r.txs.push_back(it->second);
|
||||
switch (std::get<2>(tx))
|
||||
{
|
||||
default:
|
||||
case relay_method::none:
|
||||
break;
|
||||
case relay_method::local:
|
||||
private_req.txs.push_back(std::move(std::get<1>(tx)));
|
||||
break;
|
||||
case relay_method::block:
|
||||
case relay_method::flood:
|
||||
public_req.txs.push_back(std::move(std::get<1>(tx)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
get_protocol()->relay_transactions(r, fake_context);
|
||||
m_mempool.set_relayed(txs);
|
||||
|
||||
/* All txes are sent on randomized timers per connection in
|
||||
`src/cryptonote_protocol/levin_notify.cpp.` They are either sent with
|
||||
"white noise" delays or via diffusion (Dandelion++ fluff). So
|
||||
re-relaying public and private _should_ be acceptable here. */
|
||||
const boost::uuids::uuid source = boost::uuids::nil_uuid();
|
||||
if (!public_req.txs.empty())
|
||||
get_protocol()->relay_transactions(public_req, source, epee::net_utils::zone::public_);
|
||||
if (!private_req.txs.empty())
|
||||
get_protocol()->relay_transactions(private_req, source, epee::net_utils::zone::invalid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_transaction_relayed(const cryptonote::blobdata& tx_blob)
|
||||
void core::on_transactions_relayed(const epee::span<const cryptonote::blobdata> tx_blobs, const relay_method tx_relay)
|
||||
{
|
||||
std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
|
||||
cryptonote::transaction tx;
|
||||
crypto::hash tx_hash;
|
||||
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
|
||||
std::vector<crypto::hash> tx_hashes{};
|
||||
tx_hashes.resize(tx_blobs.size());
|
||||
|
||||
cryptonote::transaction tx{};
|
||||
for (std::size_t i = 0; i < tx_blobs.size(); ++i)
|
||||
{
|
||||
LOG_ERROR("Failed to parse relayed transaction");
|
||||
return;
|
||||
if (!parse_and_validate_tx_from_blob(tx_blobs[i], tx, tx_hashes[i]))
|
||||
{
|
||||
LOG_ERROR("Failed to parse relayed transaction");
|
||||
return;
|
||||
}
|
||||
}
|
||||
txs.push_back(std::make_pair(tx_hash, std::move(tx_blob)));
|
||||
m_mempool.set_relayed(txs);
|
||||
m_mempool.set_relayed(epee::to_span(tx_hashes), tx_relay);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
|
||||
|
@ -1369,7 +1389,7 @@ namespace cryptonote
|
|||
for (const auto &tx_hash: b.tx_hashes)
|
||||
{
|
||||
cryptonote::blobdata txblob;
|
||||
CHECK_AND_ASSERT_THROW_MES(pool.get_transaction(tx_hash, txblob), "Transaction not found in pool");
|
||||
CHECK_AND_ASSERT_THROW_MES(pool.get_transaction(tx_hash, txblob, relay_category::all), "Transaction not found in pool");
|
||||
bce.txs.push_back({txblob, crypto::null_hash});
|
||||
}
|
||||
return bce;
|
||||
|
@ -1573,14 +1593,14 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_pool_transaction(const crypto::hash &id, cryptonote::blobdata& tx) const
|
||||
bool core::get_pool_transaction(const crypto::hash &id, cryptonote::blobdata& tx, relay_category tx_category) const
|
||||
{
|
||||
return m_mempool.get_transaction(id, tx);
|
||||
return m_mempool.get_transaction(id, tx, tx_category);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::pool_has_tx(const crypto::hash &id) const
|
||||
{
|
||||
return m_mempool.have_tx(id);
|
||||
return m_mempool.have_tx(id, relay_category::legacy);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_data) const
|
||||
|
|
|
@ -35,7 +35,9 @@
|
|||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include "cryptonote_core/i_core_events.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "common/download.h"
|
||||
#include "common/command_line.h"
|
||||
|
@ -46,6 +48,7 @@
|
|||
#include "cryptonote_basic/cryptonote_stat_info.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "span.h"
|
||||
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
@ -77,7 +80,7 @@ namespace cryptonote
|
|||
* limited to, communication among the Blockchain, the transaction pool,
|
||||
* any miners, and the network.
|
||||
*/
|
||||
class core: public i_miner_handler
|
||||
class core final: public i_miner_handler, public i_core_events
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -115,14 +118,29 @@ namespace cryptonote
|
|||
*
|
||||
* @param tx_blob the tx to handle
|
||||
* @param tvc metadata about the transaction's validity
|
||||
* @param keeped_by_block if the transaction has been in a block
|
||||
* @param tx_relay how the transaction was received
|
||||
* @param relayed whether or not the transaction was relayed to us
|
||||
* @param do_not_relay whether to prevent the transaction from being relayed
|
||||
*
|
||||
* @return true if the transaction was accepted, false otherwise
|
||||
*/
|
||||
bool handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, relay_method tx_relay, bool relayed);
|
||||
|
||||
/**
|
||||
* @brief handles a list of incoming transactions
|
||||
*
|
||||
* Parses incoming transactions and, if nothing is obviously wrong,
|
||||
* passes them along to the transaction pool
|
||||
*
|
||||
* @pre `tx_blobs.size() == tvc.size()`
|
||||
*
|
||||
* @param tx_blobs the txs to handle
|
||||
* @param tvc metadata about the transactions' validity
|
||||
* @param tx_relay how the transaction was received.
|
||||
* @param relayed whether or not the transactions were relayed to us
|
||||
*
|
||||
* @return true if the transactions were accepted, false otherwise
|
||||
*/
|
||||
bool handle_incoming_txs(epee::span<const tx_blob_entry> tx_blobs, epee::span<tx_verification_context> tvc, relay_method tx_relay, bool relayed);
|
||||
|
||||
/**
|
||||
* @brief handles a list of incoming transactions
|
||||
|
@ -132,13 +150,16 @@ namespace cryptonote
|
|||
*
|
||||
* @param tx_blobs the txs to handle
|
||||
* @param tvc metadata about the transactions' validity
|
||||
* @param keeped_by_block if the transactions have been in a block
|
||||
* @param tx_relay how the transaction was received.
|
||||
* @param relayed whether or not the transactions were relayed to us
|
||||
* @param do_not_relay whether to prevent the transactions from being relayed
|
||||
*
|
||||
* @return true if the transactions were accepted, false otherwise
|
||||
*/
|
||||
bool handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, relay_method tx_relay, bool relayed)
|
||||
{
|
||||
tvc.resize(tx_blobs.size());
|
||||
return handle_incoming_txs(epee::to_span(tx_blobs), epee::to_mut_span(tvc), tx_relay, relayed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief handles an incoming block
|
||||
|
@ -212,9 +233,10 @@ namespace cryptonote
|
|||
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce);
|
||||
|
||||
/**
|
||||
* @brief called when a transaction is relayed
|
||||
* @brief called when a transaction is relayed.
|
||||
* @note Should only be invoked from `levin_notify`.
|
||||
*/
|
||||
virtual void on_transaction_relayed(const cryptonote::blobdata& tx);
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) final;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -440,11 +462,11 @@ namespace cryptonote
|
|||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transactions
|
||||
* @param include_unrelayed_txes include unrelayed txes in result
|
||||
* @param include_sensitive_txes include private transactions
|
||||
*
|
||||
* @note see tx_memory_pool::get_transactions
|
||||
*/
|
||||
bool get_pool_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes = true) const;
|
||||
bool get_pool_transactions(std::vector<transaction>& txs, bool include_sensitive_txes = false) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_txpool_backlog
|
||||
|
@ -455,34 +477,34 @@ namespace cryptonote
|
|||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transactions
|
||||
* @param include_unrelayed_txes include unrelayed txes in result
|
||||
* @param include_sensitive_txes include private transactions
|
||||
*
|
||||
* @note see tx_memory_pool::get_transactions
|
||||
*/
|
||||
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
|
||||
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive_txes = false) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transactions
|
||||
* @param include_unrelayed_txes include unrelayed txes in result
|
||||
* @param include_sensitive_txes include private transactions
|
||||
*
|
||||
* @note see tx_memory_pool::get_transactions
|
||||
*/
|
||||
bool get_pool_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes = true) const;
|
||||
bool get_pool_transaction_stats(struct txpool_stats& stats, bool include_sensitive_txes = false) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transaction
|
||||
*
|
||||
* @note see tx_memory_pool::get_transaction
|
||||
*/
|
||||
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx) const;
|
||||
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx, relay_category tx_category) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info
|
||||
* @param include_unrelayed_txes include unrelayed txes in result
|
||||
* @param include_sensitive_txes include private transactions
|
||||
*
|
||||
* @note see tx_memory_pool::get_pool_transactions_and_spent_keys_info
|
||||
*/
|
||||
bool get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_unrelayed_txes = true) const;
|
||||
bool get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_txes = false) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_pool_for_rpc
|
||||
|
@ -852,11 +874,11 @@ namespace cryptonote
|
|||
* @param tx_hash the transaction's hash
|
||||
* @param blob the transaction as a blob
|
||||
* @param tx_weight the weight of the transaction
|
||||
* @param tx_relay how the transaction was received
|
||||
* @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 cryptonote::blobdata &blob, 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, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed);
|
||||
|
||||
/**
|
||||
* @brief add a new transaction to the transaction pool
|
||||
|
@ -865,15 +887,14 @@ namespace cryptonote
|
|||
*
|
||||
* @param tx the transaction to add
|
||||
* @param tvc return-by-reference metadata about the transaction's verification process
|
||||
* @param keeped_by_block whether or not the transaction has been in a block
|
||||
* @param tx_relay how the transaction was received
|
||||
* @param relayed whether or not the transaction was relayed to us
|
||||
* @param do_not_relay whether to prevent the transaction from being relayed
|
||||
*
|
||||
* @return true if the transaction is already in the transaction pool,
|
||||
* is already in a block on the Blockchain, or is successfully added
|
||||
* to the transaction pool
|
||||
*/
|
||||
bool add_new_tx(transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool add_new_tx(transaction& tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed);
|
||||
|
||||
/**
|
||||
* @copydoc Blockchain::add_new_block
|
||||
|
@ -929,8 +950,8 @@ namespace cryptonote
|
|||
bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const;
|
||||
void set_semantics_failed(const crypto::hash &tx_hash);
|
||||
|
||||
bool handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_tx_post(const tx_blob_entry &tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash);
|
||||
bool handle_incoming_tx_post(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash);
|
||||
struct tx_verification_batch_info { const cryptonote::transaction *tx; crypto::hash tx_hash; tx_verification_context &tvc; bool &result; };
|
||||
bool handle_incoming_tx_accumulated_batch(std::vector<tx_verification_batch_info> &tx_info, bool keeped_by_block);
|
||||
|
||||
|
|
44
src/cryptonote_core/i_core_events.h
Normal file
44
src/cryptonote_core/i_core_events.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_basic/blobdatatype.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
#include "span.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct i_core_events
|
||||
{
|
||||
virtual ~i_core_events() noexcept
|
||||
{}
|
||||
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0;
|
||||
};
|
||||
}
|
|
@ -115,8 +115,10 @@ namespace cryptonote
|
|||
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
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)
|
||||
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)
|
||||
{
|
||||
const bool kept_by_block = (tx_relay == relay_method::block);
|
||||
|
||||
// this should already be called with that lock, but let's make it explicit for clarity
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
|
@ -227,7 +229,7 @@ namespace cryptonote
|
|||
|
||||
crypto::hash max_used_block_id = null_hash;
|
||||
uint64_t max_used_block_height = 0;
|
||||
cryptonote::txpool_tx_meta_t meta;
|
||||
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);
|
||||
if(!ch_inp_res)
|
||||
{
|
||||
|
@ -241,11 +243,10 @@ namespace cryptonote
|
|||
meta.max_used_block_height = 0;
|
||||
meta.last_failed_height = 0;
|
||||
meta.last_failed_id = null_hash;
|
||||
meta.kept_by_block = kept_by_block;
|
||||
meta.receive_time = receive_time;
|
||||
meta.last_relayed_time = time(NULL);
|
||||
meta.relayed = relayed;
|
||||
meta.do_not_relay = do_not_relay;
|
||||
meta.set_relay_method(tx_relay);
|
||||
meta.double_spend_seen = have_tx_keyimges_as_spent(tx);
|
||||
meta.pruned = tx.pruned;
|
||||
meta.bf_padding = 0;
|
||||
|
@ -256,9 +257,10 @@ namespace cryptonote
|
|||
m_parsed_tx_cache.insert(std::make_pair(id, tx));
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
LockedTXN lock(m_blockchain);
|
||||
m_blockchain.add_txpool_tx(id, blob, meta);
|
||||
if (!insert_key_images(tx, id, kept_by_block))
|
||||
if (!insert_key_images(tx, id, tx_relay))
|
||||
return false;
|
||||
|
||||
m_blockchain.add_txpool_tx(id, blob, meta);
|
||||
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
|
||||
lock.commit();
|
||||
}
|
||||
|
@ -280,7 +282,6 @@ namespace cryptonote
|
|||
{
|
||||
//update transactions container
|
||||
meta.weight = tx_weight;
|
||||
meta.kept_by_block = kept_by_block;
|
||||
meta.fee = fee;
|
||||
meta.max_used_block_id = max_used_block_id;
|
||||
meta.max_used_block_height = max_used_block_height;
|
||||
|
@ -289,7 +290,7 @@ namespace cryptonote
|
|||
meta.receive_time = receive_time;
|
||||
meta.last_relayed_time = time(NULL);
|
||||
meta.relayed = relayed;
|
||||
meta.do_not_relay = do_not_relay;
|
||||
meta.set_relay_method(tx_relay);
|
||||
meta.double_spend_seen = false;
|
||||
meta.pruned = tx.pruned;
|
||||
meta.bf_padding = 0;
|
||||
|
@ -302,9 +303,10 @@ namespace cryptonote
|
|||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
LockedTXN lock(m_blockchain);
|
||||
m_blockchain.remove_txpool_tx(id);
|
||||
m_blockchain.add_txpool_tx(id, blob, meta);
|
||||
if (!insert_key_images(tx, id, kept_by_block))
|
||||
if (!insert_key_images(tx, id, tx_relay))
|
||||
return false;
|
||||
|
||||
m_blockchain.add_txpool_tx(id, blob, meta);
|
||||
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
|
||||
lock.commit();
|
||||
}
|
||||
|
@ -315,7 +317,7 @@ namespace cryptonote
|
|||
}
|
||||
tvc.m_added_to_pool = true;
|
||||
|
||||
if(meta.fee > 0 && !do_not_relay)
|
||||
if(meta.fee > 0 && tx_relay != relay_method::none)
|
||||
tvc.m_should_be_relayed = true;
|
||||
}
|
||||
|
||||
|
@ -331,7 +333,7 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(transaction &tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay, uint8_t version)
|
||||
bool tx_memory_pool::add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
size_t blob_size = 0;
|
||||
|
@ -339,7 +341,7 @@ namespace cryptonote
|
|||
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, keeped_by_block, relayed, do_not_relay, version);
|
||||
return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, tx_relay, relayed, version);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
size_t tx_memory_pool::get_txpool_weight() const
|
||||
|
@ -375,7 +377,7 @@ namespace cryptonote
|
|||
txpool_tx_meta_t meta;
|
||||
if (!m_blockchain.get_txpool_tx_meta(txid, meta))
|
||||
{
|
||||
MERROR("Failed to find tx in txpool");
|
||||
MERROR("Failed to find tx_meta in txpool");
|
||||
return;
|
||||
}
|
||||
// don't prune the kept_by_block ones, they're likely added because we're adding a block with those
|
||||
|
@ -384,7 +386,7 @@ namespace cryptonote
|
|||
--it;
|
||||
continue;
|
||||
}
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
|
||||
cryptonote::transaction_prefix tx;
|
||||
if (!parse_and_validate_tx_prefix_from_blob(txblob, tx))
|
||||
{
|
||||
|
@ -413,17 +415,38 @@ namespace cryptonote
|
|||
MINFO("Pool weight after pruning is larger than limit: " << m_txpool_weight << "/" << bytes);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::insert_key_images(const transaction_prefix &tx, const crypto::hash &id, bool kept_by_block)
|
||||
bool tx_memory_pool::insert_key_images(const transaction_prefix &tx, const crypto::hash &id, relay_method tx_relay)
|
||||
{
|
||||
for(const auto& in: tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
|
||||
std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
|
||||
CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block
|
||||
<< ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
|
||||
<< "tx_id=" << id );
|
||||
auto ins_res = kei_image_set.insert(id);
|
||||
CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
|
||||
|
||||
/* If any existing key-image in the set is publicly visible AND this is
|
||||
not forcibly "kept_by_block", then fail (duplicate key image). If all
|
||||
existing key images are supposed to be hidden, we silently allow so
|
||||
that the node doesn't leak knowledge of a local/stem tx. */
|
||||
bool visible = false;
|
||||
if (tx_relay != relay_method::block)
|
||||
{
|
||||
for (const crypto::hash& other_id : kei_image_set)
|
||||
visible |= m_blockchain.txpool_tx_matches_category(other_id, relay_category::legacy);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(!visible, false, "internal error: tx_relay=" << unsigned(tx_relay)
|
||||
<< ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
|
||||
<< "tx_id=" << id);
|
||||
|
||||
/* If adding a tx (hash) that already exists, fail only if the tx has
|
||||
been publicly "broadcast" previously. This way, when a private tx is
|
||||
received for the first time from a remote node, "this" node will
|
||||
respond as-if it were seen for the first time. LMDB does the
|
||||
"hard-check" on key-images, so the effect is overwriting the existing
|
||||
tx_pool metadata and "first seen" time. */
|
||||
const bool new_or_previously_private =
|
||||
kei_image_set.insert(id).second ||
|
||||
!m_blockchain.txpool_tx_matches_category(id, relay_category::legacy);
|
||||
CHECK_AND_ASSERT_MES(new_or_previously_private, false, "internal error: try to insert duplicate iterator in key_image set");
|
||||
}
|
||||
++m_cookie;
|
||||
return true;
|
||||
|
@ -475,10 +498,10 @@ namespace cryptonote
|
|||
txpool_tx_meta_t meta;
|
||||
if (!m_blockchain.get_txpool_tx_meta(id, meta))
|
||||
{
|
||||
MERROR("Failed to find tx in txpool");
|
||||
MERROR("Failed to find tx_meta in txpool");
|
||||
return false;
|
||||
}
|
||||
txblob = m_blockchain.get_txpool_tx_blob(id);
|
||||
txblob = m_blockchain.get_txpool_tx_blob(id, relay_category::all);
|
||||
auto ci = m_parsed_tx_cache.find(id);
|
||||
if (ci != m_parsed_tx_cache.end())
|
||||
{
|
||||
|
@ -533,7 +556,7 @@ namespace cryptonote
|
|||
MERROR("Failed to find tx in txpool");
|
||||
return false;
|
||||
}
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
|
||||
auto ci = m_parsed_tx_cache.find(txid);
|
||||
if (ci != m_parsed_tx_cache.end())
|
||||
{
|
||||
|
@ -611,7 +634,7 @@ namespace cryptonote
|
|||
remove.push_back(std::make_pair(txid, meta.weight));
|
||||
}
|
||||
return true;
|
||||
}, false);
|
||||
}, false, relay_category::all);
|
||||
|
||||
if (!remove.empty())
|
||||
{
|
||||
|
@ -621,7 +644,7 @@ namespace cryptonote
|
|||
const crypto::hash &txid = entry.first;
|
||||
try
|
||||
{
|
||||
cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
|
||||
cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
|
||||
cryptonote::transaction_prefix tx;
|
||||
if (!parse_and_validate_tx_prefix_from_blob(bd, tx))
|
||||
{
|
||||
|
@ -649,7 +672,7 @@ namespace cryptonote
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
//TODO: investigate whether boolean return is appropriate
|
||||
bool tx_memory_pool::get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs) const
|
||||
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
|
@ -667,8 +690,7 @@ namespace cryptonote
|
|||
{
|
||||
try
|
||||
{
|
||||
cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
|
||||
txs.push_back(std::make_pair(txid, bd));
|
||||
txs.emplace_back(txid, m_blockchain.get_txpool_tx_blob(txid, relay_category::all), meta.get_relay_method());
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
@ -678,26 +700,27 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
return true;
|
||||
}, false);
|
||||
}, false, relay_category::relayable);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs)
|
||||
void tx_memory_pool::set_relayed(const epee::span<const crypto::hash> hashes, const relay_method method)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
const time_t now = time(NULL);
|
||||
LockedTXN lock(m_blockchain);
|
||||
for (auto it = txs.begin(); it != txs.end(); ++it)
|
||||
for (const auto& hash : hashes)
|
||||
{
|
||||
try
|
||||
{
|
||||
txpool_tx_meta_t meta;
|
||||
if (m_blockchain.get_txpool_tx_meta(it->first, meta))
|
||||
if (m_blockchain.get_txpool_tx_meta(hash, meta))
|
||||
{
|
||||
meta.relayed = true;
|
||||
meta.last_relayed_time = now;
|
||||
m_blockchain.update_txpool_tx(it->first, meta);
|
||||
meta.set_relay_method(method);
|
||||
m_blockchain.update_txpool_tx(hash, meta);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
|
@ -709,18 +732,19 @@ namespace cryptonote
|
|||
lock.commit();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
|
||||
size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
|
||||
return m_blockchain.get_txpool_tx_count(include_sensitive);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::get_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes) const
|
||||
void tx_memory_pool::get_transactions(std::vector<transaction>& txs, bool include_sensitive) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
|
||||
const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
|
||||
m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
|
||||
transaction tx;
|
||||
if (!(meta.pruned ? parse_and_validate_tx_base_from_blob(*bd, tx) : parse_and_validate_tx_from_blob(*bd, tx)))
|
||||
|
@ -732,39 +756,42 @@ namespace cryptonote
|
|||
tx.set_hash(txid);
|
||||
txs.push_back(std::move(tx));
|
||||
return true;
|
||||
}, true, include_unrelayed_txes);
|
||||
}, true, category);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes) const
|
||||
void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
|
||||
const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
|
||||
m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
|
||||
txs.push_back(txid);
|
||||
return true;
|
||||
}, false, include_unrelayed_txes);
|
||||
}, false, category);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes) const
|
||||
void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
const uint64_t now = time(NULL);
|
||||
backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
|
||||
const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
|
||||
backlog.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
|
||||
m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
|
||||
backlog.push_back({meta.weight, meta.fee, meta.receive_time - now});
|
||||
return true;
|
||||
}, false, include_unrelayed_txes);
|
||||
}, false, category);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes) const
|
||||
void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_sensitive) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
const uint64_t now = time(NULL);
|
||||
const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
|
||||
std::map<uint64_t, txpool_histo> agebytes;
|
||||
stats.txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
|
||||
stats.txs_total = m_blockchain.get_txpool_tx_count(include_sensitive);
|
||||
std::vector<uint32_t> weights;
|
||||
weights.reserve(stats.txs_total);
|
||||
m_blockchain.for_all_txpool_txes([&stats, &weights, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
|
||||
|
@ -789,7 +816,8 @@ namespace cryptonote
|
|||
if (meta.double_spend_seen)
|
||||
++stats.num_double_spends;
|
||||
return true;
|
||||
}, false, include_unrelayed_txes);
|
||||
}, false, category);
|
||||
|
||||
stats.bytes_med = epee::misc_utils::median(weights);
|
||||
if (stats.txs_total > 1)
|
||||
{
|
||||
|
@ -847,8 +875,10 @@ namespace cryptonote
|
|||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
tx_infos.reserve(m_blockchain.get_txpool_tx_count());
|
||||
key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
|
||||
const relay_category category = include_sensitive_data ? relay_category::all : relay_category::broadcasted;
|
||||
const size_t count = m_blockchain.get_txpool_tx_count(include_sensitive_data);
|
||||
tx_infos.reserve(count);
|
||||
key_image_infos.reserve(count);
|
||||
m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos, include_sensitive_data](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
|
||||
tx_info txi;
|
||||
txi.id_hash = epee::string_tools::pod_to_hex(txid);
|
||||
|
@ -879,7 +909,7 @@ namespace cryptonote
|
|||
txi.double_spend_seen = meta.double_spend_seen;
|
||||
tx_infos.push_back(std::move(txi));
|
||||
return true;
|
||||
}, true, include_sensitive_data);
|
||||
}, true, category);
|
||||
|
||||
txpool_tx_meta_t meta;
|
||||
for (const key_images_container::value_type& kee : m_spent_key_images) {
|
||||
|
@ -889,30 +919,13 @@ namespace cryptonote
|
|||
ki.id_hash = epee::string_tools::pod_to_hex(k_image);
|
||||
for (const crypto::hash& tx_id_hash : kei_image_set)
|
||||
{
|
||||
if (!include_sensitive_data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
|
||||
{
|
||||
MERROR("Failed to get tx meta from txpool");
|
||||
return false;
|
||||
}
|
||||
if (!meta.relayed)
|
||||
// Do not include that transaction if in restricted mode and it's not relayed
|
||||
continue;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MERROR("Failed to get tx meta from txpool: " << e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
|
||||
if (m_blockchain.txpool_tx_matches_category(tx_id_hash, category))
|
||||
ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
|
||||
}
|
||||
|
||||
// Only return key images for which we have at least one tx that we can show for them
|
||||
if (!ki.txs_hashes.empty())
|
||||
key_image_infos.push_back(ki);
|
||||
key_image_infos.push_back(std::move(ki));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -948,18 +961,19 @@ namespace cryptonote
|
|||
txi.double_spend_seen = meta.double_spend_seen;
|
||||
tx_infos.push_back(txi);
|
||||
return true;
|
||||
}, true, false);
|
||||
}, true, relay_category::broadcasted);
|
||||
|
||||
for (const key_images_container::value_type& kee : m_spent_key_images) {
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
|
||||
for (const crypto::hash& tx_id_hash : kei_image_set)
|
||||
{
|
||||
tx_hashes.push_back(tx_id_hash);
|
||||
if (m_blockchain.txpool_tx_matches_category(tx_id_hash, relay_category::broadcasted))
|
||||
tx_hashes.push_back(tx_id_hash);
|
||||
}
|
||||
|
||||
const crypto::key_image& k_image = kee.first;
|
||||
key_image_infos[k_image] = std::move(tx_hashes);
|
||||
if (!tx_hashes.empty())
|
||||
key_image_infos[kee.first] = std::move(tx_hashes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -973,19 +987,26 @@ namespace cryptonote
|
|||
|
||||
for (const auto& image : key_images)
|
||||
{
|
||||
spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ? false : true);
|
||||
bool is_spent = false;
|
||||
const auto found = m_spent_key_images.find(image);
|
||||
if (found != m_spent_key_images.end())
|
||||
{
|
||||
for (const crypto::hash& tx_hash : found->second)
|
||||
is_spent |= m_blockchain.txpool_tx_matches_category(tx_hash, relay_category::broadcasted);
|
||||
}
|
||||
spent.push_back(is_spent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::get_transaction(const crypto::hash& id, cryptonote::blobdata& txblob) const
|
||||
bool tx_memory_pool::get_transaction(const crypto::hash& id, cryptonote::blobdata& txblob, relay_category tx_category) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
try
|
||||
{
|
||||
return m_blockchain.get_txpool_tx_blob(id, txblob);
|
||||
return m_blockchain.get_txpool_tx_blob(id, txblob, tx_category);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
@ -1009,11 +1030,11 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx(const crypto::hash &id) const
|
||||
bool tx_memory_pool::have_tx(const crypto::hash &id, relay_category tx_category) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
return m_blockchain.get_db().txpool_has_tx(id);
|
||||
return m_blockchain.get_db().txpool_has_tx(id, tx_category);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const
|
||||
|
@ -1032,7 +1053,14 @@ namespace cryptonote
|
|||
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
return m_spent_key_images.end() != m_spent_key_images.find(key_im);
|
||||
bool spent = false;
|
||||
const auto found = m_spent_key_images.find(key_im);
|
||||
if (found != m_spent_key_images.end())
|
||||
{
|
||||
for (const crypto::hash& tx_hash : found->second)
|
||||
spent |= m_blockchain.txpool_tx_matches_category(tx_hash, relay_category::broadcasted);
|
||||
}
|
||||
return spent;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::lock() const
|
||||
|
@ -1217,13 +1245,14 @@ namespace cryptonote
|
|||
<< "weight: " << meta.weight << std::endl
|
||||
<< "fee: " << print_money(meta.fee) << std::endl
|
||||
<< "kept_by_block: " << (meta.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "is_local" << (meta.is_local ? 'T' : 'F') << std::endl
|
||||
<< "double_spend_seen: " << (meta.double_spend_seen ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << meta.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << meta.max_used_block_id << std::endl
|
||||
<< "last_failed_height: " << meta.last_failed_height << std::endl
|
||||
<< "last_failed_id: " << meta.last_failed_id << std::endl;
|
||||
return true;
|
||||
}, !short_format);
|
||||
}, !short_format, relay_category::all);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -1255,7 +1284,7 @@ namespace cryptonote
|
|||
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
|
||||
{
|
||||
txpool_tx_meta_t meta;
|
||||
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
|
||||
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta) && !meta.matches(relay_category::legacy))
|
||||
{
|
||||
MERROR(" failed to find tx meta");
|
||||
continue;
|
||||
|
@ -1304,7 +1333,9 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second);
|
||||
// "local" and "stem" txes are filtered above
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second, relay_category::all);
|
||||
|
||||
cryptonote::transaction tx;
|
||||
|
||||
// Skip transactions that are not ready to be
|
||||
|
@ -1379,7 +1410,7 @@ namespace cryptonote
|
|||
remove.insert(txid);
|
||||
}
|
||||
return true;
|
||||
}, false);
|
||||
}, false, relay_category::all);
|
||||
|
||||
size_t n_removed = 0;
|
||||
if (!remove.empty())
|
||||
|
@ -1389,7 +1420,7 @@ namespace cryptonote
|
|||
{
|
||||
try
|
||||
{
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
|
||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
|
||||
cryptonote::transaction tx;
|
||||
if (!parse_and_validate_tx_from_blob(txblob, tx)) // remove pruned ones on startup, they're meant to be temporary
|
||||
{
|
||||
|
@ -1450,7 +1481,7 @@ namespace cryptonote
|
|||
remove.push_back(txid);
|
||||
return true;
|
||||
}
|
||||
if (!insert_key_images(tx, txid, meta.kept_by_block))
|
||||
if (!insert_key_images(tx, txid, meta.get_relay_method()))
|
||||
{
|
||||
MFATAL("Failed to insert key images from txpool tx");
|
||||
return false;
|
||||
|
@ -1458,7 +1489,7 @@ namespace cryptonote
|
|||
m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.weight, meta.receive_time), txid);
|
||||
m_txpool_weight += meta.weight;
|
||||
return true;
|
||||
}, true);
|
||||
}, true, relay_category::all);
|
||||
if (!r)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -32,17 +32,20 @@
|
|||
#include "include_base_utils.h"
|
||||
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include "span.h"
|
||||
#include "string_tools.h"
|
||||
#include "syncobj.h"
|
||||
#include "math_helper.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/verification_context.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
|
@ -105,9 +108,10 @@ namespace cryptonote
|
|||
* @copydoc add_tx(transaction&, tx_verification_context&, bool, bool, uint8_t)
|
||||
*
|
||||
* @param id the transaction's hash
|
||||
* @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, 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, relay_method tx_relay, bool relayed, uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief add a transaction to the transaction pool
|
||||
|
@ -119,14 +123,13 @@ namespace cryptonote
|
|||
*
|
||||
* @param tx the transaction to be added
|
||||
* @param tvc return-by-reference status about the transaction verification
|
||||
* @param kept_by_block has this transaction been in a block?
|
||||
* @tx_relay how the transaction was received
|
||||
* @param relayed was this transaction from the network or a local client?
|
||||
* @param do_not_relay to avoid relaying the transaction to the network
|
||||
* @param version the version used to create the transaction
|
||||
*
|
||||
* @return true if the transaction passes validations, otherwise false
|
||||
*/
|
||||
bool add_tx(transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
|
||||
bool add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief takes a transaction with the given hash from the pool
|
||||
|
@ -149,10 +152,11 @@ namespace cryptonote
|
|||
* @brief checks if the pool has a transaction with the given hash
|
||||
*
|
||||
* @param id the hash to look for
|
||||
* @param tx_category a filter for txes
|
||||
*
|
||||
* @return true if the transaction is in the pool, otherwise false
|
||||
* @return true if the transaction is in the pool and meets tx_category requirements
|
||||
*/
|
||||
bool have_tx(const crypto::hash &id) const;
|
||||
bool have_tx(const crypto::hash &id, relay_category tx_category) const;
|
||||
|
||||
/**
|
||||
* @brief action to take when notified of a block added to the blockchain
|
||||
|
@ -236,37 +240,37 @@ namespace cryptonote
|
|||
* @brief get a list of all transactions in the pool
|
||||
*
|
||||
* @param txs return-by-reference the list of transactions
|
||||
* @param include_unrelayed_txes include unrelayed txes in the result
|
||||
* @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
|
||||
*
|
||||
*/
|
||||
void get_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes = true) const;
|
||||
void get_transactions(std::vector<transaction>& txs, bool include_sensitive = false) const;
|
||||
|
||||
/**
|
||||
* @brief get a list of all transaction hashes in the pool
|
||||
*
|
||||
* @param txs return-by-reference the list of transactions
|
||||
* @param include_unrelayed_txes include unrelayed txes in the result
|
||||
* @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
|
||||
*
|
||||
*/
|
||||
void get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
|
||||
void get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive = false) const;
|
||||
|
||||
/**
|
||||
* @brief get (weight, fee, receive time) for all transaction in the pool
|
||||
*
|
||||
* @param txs return-by-reference that data
|
||||
* @param include_unrelayed_txes include unrelayed txes in the result
|
||||
* @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
|
||||
*
|
||||
*/
|
||||
void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes = true) const;
|
||||
void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive = false) const;
|
||||
|
||||
/**
|
||||
* @brief get a summary statistics of all transaction hashes in the pool
|
||||
*
|
||||
* @param stats return-by-reference the pool statistics
|
||||
* @param include_unrelayed_txes include unrelayed txes in the result
|
||||
* @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
|
||||
*
|
||||
*/
|
||||
void get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes = true) const;
|
||||
void get_transaction_stats(struct txpool_stats& stats, bool include_sensitive = false) const;
|
||||
|
||||
/**
|
||||
* @brief get information about all transactions and key images in the pool
|
||||
|
@ -275,11 +279,12 @@ namespace cryptonote
|
|||
*
|
||||
* @param tx_infos return-by-reference the transactions' information
|
||||
* @param key_image_infos return-by-reference the spent key images' information
|
||||
* @param include_sensitive_data include unrelayed txes and fields that are sensitive to the node privacy
|
||||
* @param include_sensitive_data return stempool, anonymity-pool, and unrelayed
|
||||
* txes and fields that are sensitive to the node privacy
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_data = true) const;
|
||||
bool get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_data = false) const;
|
||||
|
||||
/**
|
||||
* @brief get information about all transactions and key images in the pool
|
||||
|
@ -308,10 +313,11 @@ namespace cryptonote
|
|||
*
|
||||
* @param h the hash of the transaction to get
|
||||
* @param tx return-by-reference the transaction blob requested
|
||||
* @param tx_relay last relay method us
|
||||
*
|
||||
* @return true if the transaction is found, otherwise false
|
||||
*/
|
||||
bool get_transaction(const crypto::hash& h, cryptonote::blobdata& txblob) const;
|
||||
bool get_transaction(const crypto::hash& h, cryptonote::blobdata& txblob, relay_category tx_category) const;
|
||||
|
||||
/**
|
||||
* @brief get a list of all relayable transactions and their hashes
|
||||
|
@ -326,21 +332,22 @@ namespace cryptonote
|
|||
*
|
||||
* @return true
|
||||
*/
|
||||
bool get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>>& txs) const;
|
||||
bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs) const;
|
||||
|
||||
/**
|
||||
* @brief tell the pool that certain transactions were just relayed
|
||||
*
|
||||
* @param txs the list of transactions (and their hashes)
|
||||
* @param hashes list of tx hashes that are about to be relayed
|
||||
* @param tx_relay update how the tx left this node
|
||||
*/
|
||||
void set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>>& txs);
|
||||
void set_relayed(epee::span<const crypto::hash> hashes, relay_method tx_relay);
|
||||
|
||||
/**
|
||||
* @brief get the total number of transactions in the pool
|
||||
*
|
||||
* @return the number of transactions in the pool
|
||||
*/
|
||||
size_t get_transactions_count(bool include_unrelayed_txes = true) const;
|
||||
size_t get_transactions_count(bool include_sensitive = false) const;
|
||||
|
||||
/**
|
||||
* @brief get a string containing human-readable pool information
|
||||
|
@ -441,7 +448,7 @@ namespace cryptonote
|
|||
*
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool insert_key_images(const transaction_prefix &tx, const crypto::hash &txid, bool kept_by_block);
|
||||
bool insert_key_images(const transaction_prefix &tx, const crypto::hash &txid, relay_method tx_relay);
|
||||
|
||||
/**
|
||||
* @brief remove old transactions from the pool
|
||||
|
@ -544,7 +551,7 @@ namespace cryptonote
|
|||
* transaction on the assumption that the original will not be in a
|
||||
* block again.
|
||||
*/
|
||||
typedef std::unordered_map<crypto::key_image, std::unordered_set<crypto::hash> > key_images_container;
|
||||
typedef std::unordered_map<crypto::key_image, std::unordered_set<crypto::hash>> key_images_container;
|
||||
|
||||
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
|
||||
public:
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace cryptonote
|
|||
|
||||
//----------------- i_bc_protocol_layout ---------------------------------------
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone);
|
||||
//----------------------------------------------------------------------------------
|
||||
//bool get_payload_sync_data(HANDSHAKE_DATA::request& hshd, cryptonote_connection_context& context);
|
||||
bool should_drop_connection(cryptonote_connection_context& context, uint32_t next_stripe);
|
||||
|
|
|
@ -455,7 +455,7 @@ namespace cryptonote
|
|||
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
|
||||
{
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_core.handle_incoming_tx(*tx_blob_it, tvc, true, true, false);
|
||||
m_core.handle_incoming_tx(*tx_blob_it, tvc, relay_method::block, true);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
|
||||
|
@ -619,7 +619,7 @@ namespace cryptonote
|
|||
{
|
||||
MDEBUG("Incoming tx " << tx_hash << " not in pool, adding");
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true, false) || tvc.m_verifivation_failed)
|
||||
if(!m_core.handle_incoming_tx(tx_blob, tvc, relay_method::block, true) || tvc.m_verifivation_failed)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
|
@ -667,13 +667,13 @@ namespace cryptonote
|
|||
drop_connection(context, false, false);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t tx_idx = 0;
|
||||
for(auto& tx_hash: new_block.tx_hashes)
|
||||
{
|
||||
cryptonote::blobdata txblob;
|
||||
if(m_core.get_pool_transaction(tx_hash, txblob))
|
||||
if(m_core.get_pool_transaction(tx_hash, txblob, relay_category::broadcasted))
|
||||
{
|
||||
have_tx.push_back({txblob, crypto::null_hash});
|
||||
}
|
||||
|
@ -702,7 +702,7 @@ namespace cryptonote
|
|||
need_tx_indices.push_back(tx_idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
++tx_idx;
|
||||
}
|
||||
|
||||
|
@ -909,8 +909,8 @@ namespace cryptonote
|
|||
newtxs.reserve(arg.txs.size());
|
||||
for (size_t i = 0; i < arg.txs.size(); ++i)
|
||||
{
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_core.handle_incoming_tx({arg.txs[i], crypto::null_hash}, tvc, false, true, false);
|
||||
cryptonote::tx_verification_context tvc{};
|
||||
m_core.handle_incoming_tx({arg.txs[i], crypto::null_hash}, tvc, relay_method::flood, true);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
|
||||
|
@ -925,7 +925,7 @@ namespace cryptonote
|
|||
if(arg.txs.size())
|
||||
{
|
||||
//TODO: add announce usage here
|
||||
relay_transactions(arg, context);
|
||||
relay_transactions(arg, context.m_connection_id, context.m_remote_address.get_zone());
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -1316,7 +1316,7 @@ namespace cryptonote
|
|||
TIME_MEASURE_START(transactions_process_time);
|
||||
num_txs += block_entry.txs.size();
|
||||
std::vector<tx_verification_context> tvc;
|
||||
m_core.handle_incoming_txs(block_entry.txs, tvc, true, true, false);
|
||||
m_core.handle_incoming_txs(block_entry.txs, tvc, relay_method::block, true);
|
||||
if (tvc.size() != block_entry.txs.size())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Internal error: tvc.size() != block_entry.txs.size()");
|
||||
|
@ -2344,14 +2344,14 @@ skip:
|
|||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
|
||||
bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone)
|
||||
{
|
||||
for(auto& tx_blob : arg.txs)
|
||||
m_core.on_transaction_relayed(tx_blob);
|
||||
|
||||
// no check for success, so tell core they're relayed unconditionally
|
||||
m_p2p->send_txs(std::move(arg.txs), exclude_context.m_remote_address.get_zone(), exclude_context.m_connection_id, m_core.pad_transactions());
|
||||
return true;
|
||||
/* Push all outgoing transactions to this function. The behavior needs to
|
||||
identify how the transaction is going to be relayed, and then update the
|
||||
local mempool before doing the relay. The code was already updating the
|
||||
DB twice on received transactions - it is difficult to workaround this
|
||||
due to the internal design. */
|
||||
return m_p2p->send_txs(std::move(arg.txs), zone, source, m_core, m_core.pad_transactions()) != epee::net_utils::zone::invalid;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace cryptonote
|
|||
struct i_cryptonote_protocol
|
||||
{
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone)=0;
|
||||
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
|
||||
};
|
||||
|
||||
|
@ -54,7 +54,7 @@ namespace cryptonote
|
|||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
43
src/cryptonote_protocol/enums.h
Normal file
43
src/cryptonote_protocol/enums.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//! Methods tracking how a tx was received and relayed
|
||||
enum class relay_method : std::uint8_t
|
||||
{
|
||||
none = 0, //!< Received via RPC with `do_not_relay` set
|
||||
local, //!< Received via RPC; trying to send over i2p/tor, etc.
|
||||
block, //!< Received in block, takes precedence over others
|
||||
flood //!< Received/sent over public networks
|
||||
};
|
||||
}
|
37
src/cryptonote_protocol/fwd.h
Normal file
37
src/cryptonote_protocol/fwd.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class core;
|
||||
struct cryptonote_connection_context;
|
||||
struct i_core_events;
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include "byte_slice.h"
|
||||
#include "cryptonote_basic/blobdatatype.h"
|
||||
#include "cryptonote_protocol/fwd.h"
|
||||
#include "net/enums.h"
|
||||
#include "span.h"
|
||||
|
||||
|
@ -51,11 +52,6 @@ namespace nodetool
|
|||
template<typename> struct p2p_connection_context_t;
|
||||
}
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct cryptonote_connection_context;
|
||||
}
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
namespace levin
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_protocol/fwd.h"
|
||||
#include "cryptonote_protocol/levin_notify.h"
|
||||
#include "warnings.h"
|
||||
#include "net/abstract_tcp_server2.h"
|
||||
|
@ -336,7 +337,7 @@ namespace nodetool
|
|||
virtual void callback(p2p_connection_context& context);
|
||||
//----------------- i_p2p_endpoint -------------------------------------------------------------
|
||||
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections);
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs);
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, bool pad_txs);
|
||||
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
|
||||
|
|
|
@ -2053,13 +2053,18 @@ namespace nodetool
|
|||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)
|
||||
epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const bool pad_txs)
|
||||
{
|
||||
namespace enet = epee::net_utils;
|
||||
|
||||
const auto send = [&txs, &source, pad_txs] (std::pair<const enet::zone, network_zone>& network)
|
||||
const auto send = [&txs, &source, &core, pad_txs] (std::pair<const enet::zone, network_zone>& network)
|
||||
{
|
||||
if (network.second.m_notifier.send_txs(std::move(txs), source, (pad_txs || network.first != enet::zone::public_)))
|
||||
const bool is_public = (network.first == enet::zone::public_);
|
||||
const cryptonote::relay_method tx_relay = is_public ?
|
||||
cryptonote::relay_method::flood : cryptonote::relay_method::local;
|
||||
|
||||
core.on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
if (network.second.m_notifier.send_txs(std::move(txs), source, (pad_txs || !is_public)))
|
||||
return network.first;
|
||||
return enet::zone::invalid;
|
||||
};
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
#include "cryptonote_basic/blobdatatype.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
#include "cryptonote_protocol/fwd.h"
|
||||
#include "net/enums.h"
|
||||
#include "net/net_utils_base.h"
|
||||
#include "p2p_protocol_defs.h"
|
||||
|
@ -48,7 +50,7 @@ namespace nodetool
|
|||
struct i_p2p_endpoint
|
||||
{
|
||||
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0;
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)=0;
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, bool pad_txs)=0;
|
||||
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
|
||||
|
@ -73,7 +75,7 @@ namespace nodetool
|
|||
{
|
||||
return false;
|
||||
}
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)
|
||||
virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const bool pad_txs)
|
||||
{
|
||||
return epee::net_utils::zone::invalid;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/uuid/nil_generator.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "string_tools.h"
|
||||
using namespace epee;
|
||||
|
@ -1095,9 +1096,8 @@ namespace cryptonote
|
|||
}
|
||||
res.sanity_check_failed = false;
|
||||
|
||||
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
|
||||
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed)
|
||||
tx_verification_context tvc{};
|
||||
if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, (req.do_not_relay ? relay_method::none : relay_method::local), false) || tvc.m_verifivation_failed)
|
||||
{
|
||||
res.status = "Failed";
|
||||
std::string reason = "";
|
||||
|
@ -1142,7 +1142,7 @@ namespace cryptonote
|
|||
|
||||
NOTIFY_NEW_TRANSACTIONS::request r;
|
||||
r.txs.push_back(tx_blob);
|
||||
m_core.get_protocol()->relay_transactions(r, fake_context);
|
||||
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid);
|
||||
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
|
@ -2370,7 +2370,7 @@ namespace cryptonote
|
|||
if (req.txids.empty())
|
||||
{
|
||||
std::vector<transaction> pool_txs;
|
||||
bool r = m_core.get_pool_transactions(pool_txs);
|
||||
bool r = m_core.get_pool_transactions(pool_txs, true);
|
||||
if (!r)
|
||||
{
|
||||
res.status = "Failed to get txpool contents";
|
||||
|
@ -2747,13 +2747,11 @@ namespace cryptonote
|
|||
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
|
||||
|
||||
cryptonote::blobdata txblob;
|
||||
bool r = m_core.get_pool_transaction(txid, txblob);
|
||||
if (r)
|
||||
if (!m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
|
||||
{
|
||||
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
|
||||
NOTIFY_NEW_TRANSACTIONS::request r;
|
||||
r.txs.push_back(txblob);
|
||||
m_core.get_protocol()->relay_transactions(r, fake_context);
|
||||
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid);
|
||||
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
|
||||
}
|
||||
else
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "daemon_handler.h"
|
||||
|
||||
#include <boost/uuid/nil_generator.hpp>
|
||||
// likely included by daemon_handler.h's includes,
|
||||
// but including here for clarity
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
|
@ -288,10 +289,9 @@ namespace rpc
|
|||
return;
|
||||
}
|
||||
|
||||
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
|
||||
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
|
||||
if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, false, false, !relay) || tvc.m_verifivation_failed)
|
||||
if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, (relay ? relay_method::local : relay_method::none), false) || tvc.m_verifivation_failed)
|
||||
{
|
||||
if (tvc.m_verifivation_failed)
|
||||
{
|
||||
|
@ -368,7 +368,7 @@ namespace rpc
|
|||
|
||||
NOTIFY_NEW_TRANSACTIONS::request r;
|
||||
r.txs.push_back(tx_blob);
|
||||
m_core.get_protocol()->relay_transactions(r, fake_context);
|
||||
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid);
|
||||
|
||||
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
|
||||
res.status = Message::STATUS_OK;
|
||||
|
|
|
@ -160,8 +160,8 @@ string tx2str(const cryptonote::transaction& tx, const cryptonote::hash256& tx_h
|
|||
return ss.str();
|
||||
}*/
|
||||
|
||||
bool tests::proxy_core::handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) {
|
||||
if (!keeped_by_block)
|
||||
bool tests::proxy_core::handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed) {
|
||||
if (tx_relay != cryptonote::relay_method::block)
|
||||
return true;
|
||||
|
||||
crypto::hash tx_hash = null_hash;
|
||||
|
@ -190,13 +190,13 @@ bool tests::proxy_core::handle_incoming_tx(const cryptonote::tx_blob_entry& tx_b
|
|||
return true;
|
||||
}
|
||||
|
||||
bool tests::proxy_core::handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||
bool tests::proxy_core::handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed)
|
||||
{
|
||||
tvc.resize(tx_blobs.size());
|
||||
size_t i = 0;
|
||||
for (const auto &tx_blob: tx_blobs)
|
||||
{
|
||||
if (!handle_incoming_tx(tx_blob, tvc[i], keeped_by_block, relayed, do_not_relay))
|
||||
if (!handle_incoming_tx(tx_blob, tvc[i], tx_relay, relayed))
|
||||
return false;
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/verification_context.h"
|
||||
#include "cryptonote_core/i_core_events.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace tests
|
||||
|
@ -51,7 +52,7 @@ namespace tests
|
|||
: height(_height), id(_id), longhash(_longhash), blk(_blk), blob(_blob), txes(_txes) { }
|
||||
};
|
||||
|
||||
class proxy_core
|
||||
class proxy_core : public cryptonote::i_core_events
|
||||
{
|
||||
cryptonote::block m_genesis;
|
||||
std::list<crypto::hash> m_known_block_list;
|
||||
|
@ -75,8 +76,8 @@ namespace tests
|
|||
bool get_stat_info(cryptonote::core_stat_info& st_inf){return true;}
|
||||
bool have_block(const crypto::hash& id);
|
||||
void get_blockchain_top(uint64_t& height, crypto::hash& top_id);
|
||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
|
||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
||||
bool handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true);
|
||||
void pause_mine(){}
|
||||
void resume_mine(){}
|
||||
|
@ -90,9 +91,9 @@ namespace tests
|
|||
bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; }
|
||||
uint64_t get_target_blockchain_height() const { return 1; }
|
||||
size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; }
|
||||
virtual void on_transaction_relayed(const cryptonote::blobdata& tx) {}
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, cryptonote::relay_method tx_relay) {}
|
||||
cryptonote::network_type get_nettype() const { return cryptonote::MAINNET; }
|
||||
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob) const { return false; }
|
||||
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob, cryptonote::relay_category tx_category) const { return false; }
|
||||
bool pool_has_tx(const crypto::hash &txid) const { return false; }
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::vector<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::vector<cryptonote::blobdata>& txs) const { return false; }
|
||||
bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::vector<cryptonote::transaction>& txs, std::vector<crypto::hash>& missed_txs) const { return false; }
|
||||
|
|
|
@ -40,6 +40,7 @@ set(core_tests_sources
|
|||
ring_signature_1.cpp
|
||||
transaction_tests.cpp
|
||||
tx_validation.cpp
|
||||
tx_pool.cpp
|
||||
v2_tests.cpp
|
||||
rct.cpp
|
||||
bulletproofs.cpp
|
||||
|
@ -57,6 +58,7 @@ set(core_tests_headers
|
|||
integer_overflow.h
|
||||
multisig.h
|
||||
ring_signature_1.h
|
||||
tx_pool.h
|
||||
transaction_tests.h
|
||||
tx_validation.h
|
||||
v2_tests.h
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
#include "misc_language.h"
|
||||
|
||||
|
@ -108,17 +109,17 @@ typedef serialized_object<cryptonote::transaction> serialized_transaction;
|
|||
|
||||
struct event_visitor_settings
|
||||
{
|
||||
int valid_mask;
|
||||
bool txs_keeped_by_block;
|
||||
int mask;
|
||||
|
||||
enum settings
|
||||
{
|
||||
set_txs_keeped_by_block = 1 << 0
|
||||
set_txs_keeped_by_block = 1 << 0,
|
||||
set_txs_do_not_relay = 1 << 1,
|
||||
set_local_relay = 1 << 2
|
||||
};
|
||||
|
||||
event_visitor_settings(int a_valid_mask = 0, bool a_txs_keeped_by_block = false)
|
||||
: valid_mask(a_valid_mask)
|
||||
, txs_keeped_by_block(a_txs_keeped_by_block)
|
||||
event_visitor_settings(int a_mask = 0)
|
||||
: mask(a_mask)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -128,8 +129,7 @@ private:
|
|||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int /*version*/)
|
||||
{
|
||||
ar & valid_mask;
|
||||
ar & txs_keeped_by_block;
|
||||
ar & mask;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -503,7 +503,7 @@ private:
|
|||
t_test_class& m_validator;
|
||||
size_t m_ev_index;
|
||||
|
||||
bool m_txs_keeped_by_block;
|
||||
cryptonote::relay_method m_tx_relay;
|
||||
|
||||
public:
|
||||
push_core_event_visitor(cryptonote::core& c, const std::vector<test_event_entry>& events, t_test_class& validator)
|
||||
|
@ -511,7 +511,7 @@ public:
|
|||
, m_events(events)
|
||||
, m_validator(validator)
|
||||
, m_ev_index(0)
|
||||
, m_txs_keeped_by_block(false)
|
||||
, m_tx_relay(cryptonote::relay_method::flood)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -530,9 +530,21 @@ public:
|
|||
{
|
||||
log_event("event_visitor_settings");
|
||||
|
||||
if (settings.valid_mask & event_visitor_settings::set_txs_keeped_by_block)
|
||||
if (settings.mask & event_visitor_settings::set_txs_keeped_by_block)
|
||||
{
|
||||
m_txs_keeped_by_block = settings.txs_keeped_by_block;
|
||||
m_tx_relay = cryptonote::relay_method::block;
|
||||
}
|
||||
else if (settings.mask & event_visitor_settings::set_local_relay)
|
||||
{
|
||||
m_tx_relay = cryptonote::relay_method::local;
|
||||
}
|
||||
else if (settings.mask & event_visitor_settings::set_txs_do_not_relay)
|
||||
{
|
||||
m_tx_relay = cryptonote::relay_method::none;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tx_relay = cryptonote::relay_method::flood;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -544,7 +556,7 @@ public:
|
|||
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
size_t pool_size = m_c.get_pool_transactions_count();
|
||||
m_c.handle_incoming_tx({t_serializable_object_to_blob(tx), crypto::null_hash}, tvc, m_txs_keeped_by_block, false, false);
|
||||
m_c.handle_incoming_tx({t_serializable_object_to_blob(tx), crypto::null_hash}, tvc, m_tx_relay, false);
|
||||
bool tx_added = pool_size + 1 == m_c.get_pool_transactions_count();
|
||||
bool r = m_validator.check_tx_verification_context(tvc, tx_added, m_ev_index, tx);
|
||||
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
|
||||
|
@ -564,7 +576,7 @@ public:
|
|||
tvcs.push_back(tvc0);
|
||||
}
|
||||
size_t pool_size = m_c.get_pool_transactions_count();
|
||||
m_c.handle_incoming_txs(tx_blobs, tvcs, m_txs_keeped_by_block, false, false);
|
||||
m_c.handle_incoming_txs(tx_blobs, tvcs, m_tx_relay, false);
|
||||
size_t tx_added = m_c.get_pool_transactions_count() - pool_size;
|
||||
bool r = m_validator.check_tx_verification_context_array(tvcs, tx_added, m_ev_index, txs);
|
||||
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
|
||||
|
@ -644,7 +656,7 @@ public:
|
|||
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
size_t pool_size = m_c.get_pool_transactions_count();
|
||||
m_c.handle_incoming_tx(sr_tx.data, tvc, m_txs_keeped_by_block, false, false);
|
||||
m_c.handle_incoming_tx(sr_tx.data, tvc, m_tx_relay, false);
|
||||
bool tx_added = pool_size + 1 == m_c.get_pool_transactions_count();
|
||||
|
||||
cryptonote::transaction tx;
|
||||
|
@ -955,7 +967,7 @@ inline bool do_replay_file(const std::string& filename)
|
|||
|
||||
#define MAKE_MINER_TX_MANUALLY(TX, BLK) MAKE_MINER_TX_AND_KEY_MANUALLY(TX, BLK, 0)
|
||||
|
||||
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT, VAL) VEC_EVENTS.push_back(event_visitor_settings(SETT, VAL));
|
||||
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT) VEC_EVENTS.push_back(event_visitor_settings(SETT));
|
||||
|
||||
#define GENERATE(filename, genclass) \
|
||||
{ \
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "chaingen_tests_list.h"
|
||||
#include "common/util.h"
|
||||
#include "common/command_line.h"
|
||||
#include "tx_pool.h"
|
||||
#include "transaction_tests.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
@ -155,6 +156,12 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_tx_output_is_not_txout_to_key);
|
||||
GENERATE_AND_PLAY(gen_tx_signatures_are_invalid);
|
||||
|
||||
// Mempool
|
||||
GENERATE_AND_PLAY(txpool_spend_key_public);
|
||||
GENERATE_AND_PLAY(txpool_spend_key_all);
|
||||
GENERATE_AND_PLAY(txpool_double_spend_norelay);
|
||||
GENERATE_AND_PLAY(txpool_double_spend_local);
|
||||
|
||||
// Double spend
|
||||
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);
|
||||
GENERATE_AND_PLAY(gen_double_spend_in_tx<true>);
|
||||
|
|
|
@ -46,7 +46,7 @@ bool gen_double_spend_in_different_chains::generate(std::vector<test_event_entry
|
|||
{
|
||||
INIT_DOUBLE_SPEND_TEST();
|
||||
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, true);
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block);
|
||||
MAKE_TX(events, tx_1, bob_account, alice_account, send_amount / 2 - TESTS_DEFAULT_FEE, blk_1);
|
||||
events.pop_back();
|
||||
MAKE_TX(events, tx_2, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
|
||||
|
@ -96,3 +96,4 @@ bool gen_double_spend_in_different_chains::check_double_spend(cryptonote::core&
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even
|
|||
if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1, 0))
|
||||
return false;
|
||||
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block);
|
||||
SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
events.push_back(tx_1);
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
|
@ -163,7 +163,7 @@ bool gen_double_spend_in_the_same_block<txs_keeped_by_block>::generate(std::vect
|
|||
INIT_DOUBLE_SPEND_TEST();
|
||||
|
||||
DO_CALLBACK(events, "mark_last_valid_block");
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block);
|
||||
SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0);
|
||||
|
||||
MAKE_TX_LIST_START(events, txs_1, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
|
||||
cryptonote::transaction tx_1 = txs_1.front();
|
||||
|
@ -190,7 +190,7 @@ bool gen_double_spend_in_different_blocks<txs_keeped_by_block>::generate(std::ve
|
|||
INIT_DOUBLE_SPEND_TEST();
|
||||
|
||||
DO_CALLBACK(events, "mark_last_valid_block");
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block);
|
||||
SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0);
|
||||
|
||||
// Create two identical transactions, but don't push it to events list
|
||||
MAKE_TX(events, tx_blk_2, bob_account, alice_account, send_amount - TESTS_DEFAULT_FEE, blk_1);
|
||||
|
@ -220,7 +220,7 @@ bool gen_double_spend_in_alt_chain_in_the_same_block<txs_keeped_by_block>::gener
|
|||
{
|
||||
INIT_DOUBLE_SPEND_TEST();
|
||||
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block);
|
||||
SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0);
|
||||
|
||||
// Main chain
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_account);
|
||||
|
@ -255,7 +255,7 @@ bool gen_double_spend_in_alt_chain_in_different_blocks<txs_keeped_by_block>::gen
|
|||
{
|
||||
INIT_DOUBLE_SPEND_TEST();
|
||||
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block);
|
||||
SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0);
|
||||
|
||||
// Main chain
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_account);
|
||||
|
|
561
tests/core_tests/tx_pool.cpp
Normal file
561
tests/core_tests/tx_pool.cpp
Normal file
|
@ -0,0 +1,561 @@
|
|||
// Copyright (c) 2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "tx_pool.h"
|
||||
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <limits>
|
||||
#include "string_tools.h"
|
||||
|
||||
#define INIT_MEMPOOL_TEST() \
|
||||
uint64_t send_amount = 1000; \
|
||||
uint64_t ts_start = 1338224400; \
|
||||
GENERATE_ACCOUNT(miner_account); \
|
||||
GENERATE_ACCOUNT(bob_account); \
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); \
|
||||
REWIND_BLOCKS(events, blk_0r, blk_0, miner_account); \
|
||||
|
||||
|
||||
txpool_base::txpool_base()
|
||||
: test_chain_unit_base()
|
||||
, m_broadcasted_tx_count(0)
|
||||
, m_all_tx_count(0)
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(txpool_spend_key_public, increase_broadcasted_tx_count);
|
||||
REGISTER_CALLBACK_METHOD(txpool_spend_key_public, increase_all_tx_count);
|
||||
REGISTER_CALLBACK_METHOD(txpool_spend_key_public, check_txpool_spent_keys);
|
||||
}
|
||||
|
||||
bool txpool_base::increase_broadcasted_tx_count(cryptonote::core& /*c*/, size_t /*ev_index*/, const std::vector<test_event_entry>& /*events*/)
|
||||
{
|
||||
++m_broadcasted_tx_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_base::increase_all_tx_count(cryptonote::core& /*c*/, size_t /*ev_index*/, const std::vector<test_event_entry>& /*events*/)
|
||||
{
|
||||
++m_all_tx_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_base::check_txpool_spent_keys(cryptonote::core& c, size_t /*ev_index*/, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<cryptonote::tx_info> infos{};
|
||||
std::vector<cryptonote::spent_key_image_info> key_images{};
|
||||
if (!c.get_pool_transactions_and_spent_keys_info(infos, key_images) || infos.size() != m_broadcasted_tx_count || key_images.size() != m_broadcasted_tx_count)
|
||||
{
|
||||
MERROR("Failed broadcasted spent keys retrieval - Expected Broadcasted Count: " << m_broadcasted_tx_count << " Actual Info Count: " << infos.size() << " Actual Key Image Count: " << key_images.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
infos.clear();
|
||||
key_images.clear();
|
||||
if (!c.get_pool_transactions_and_spent_keys_info(infos, key_images, false) || infos.size() != m_broadcasted_tx_count || key_images.size() != m_broadcasted_tx_count)
|
||||
{
|
||||
MERROR("Failed broadcasted spent keys retrieval - Expected Broadcasted Count: " << m_broadcasted_tx_count << " Actual Info Count: " << infos.size() << " Actual Key Image Count: " << key_images.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
infos.clear();
|
||||
key_images.clear();
|
||||
if (!c.get_pool_transactions_and_spent_keys_info(infos, key_images, true) || infos.size() != m_all_tx_count || key_images.size() != m_all_tx_count)
|
||||
{
|
||||
MERROR("Failed all spent keys retrieval - Expected All Count: " << m_all_tx_count << " Actual Info Count: " << infos.size() << " Actual Key Image Count: " << key_images.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_spend_key_public::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
INIT_MEMPOOL_TEST();
|
||||
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
|
||||
DO_CALLBACK(events, "increase_broadcasted_tx_count");
|
||||
DO_CALLBACK(events, "increase_all_tx_count");
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_spend_key_all::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
INIT_MEMPOOL_TEST();
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_do_not_relay);
|
||||
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
|
||||
DO_CALLBACK(events, "increase_all_tx_count");
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
txpool_double_spend_base::txpool_double_spend_base()
|
||||
: txpool_base()
|
||||
, m_broadcasted_hashes()
|
||||
, m_no_relay_hashes()
|
||||
, m_all_hashes()
|
||||
, m_no_new_index(0)
|
||||
, m_new_timestamp_index(0)
|
||||
, m_last_tx(crypto::hash{})
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, mark_no_new);
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, mark_timestamp_change);
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, timestamp_change_pause);
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, check_unchanged);
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, check_new_broadcasted);
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, check_new_hidden);
|
||||
REGISTER_CALLBACK_METHOD(txpool_double_spend_base, check_new_no_relay);
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::mark_no_new(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
|
||||
{
|
||||
m_no_new_index = ev_index + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::mark_timestamp_change(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
|
||||
{
|
||||
m_new_timestamp_index = ev_index + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::timestamp_change_pause(cryptonote::core& /*c*/, size_t /*ev_index*/, const std::vector<test_event_entry>& /*events*/)
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds{1} + boost::chrono::milliseconds{100});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::check_changed(cryptonote::core& c, const size_t ev_index, relay_test condition)
|
||||
{
|
||||
const std::size_t public_hash_count = m_broadcasted_hashes.size();
|
||||
const std::size_t all_hash_count = m_all_hashes.size();
|
||||
|
||||
const std::size_t new_broadcasted_hash_count = m_broadcasted_hashes.size() + unsigned(condition == relay_test::broadcasted);
|
||||
const std::size_t new_all_hash_count = m_all_hashes.size() + unsigned(condition == relay_test::hidden) + unsigned(condition == relay_test::no_relay);
|
||||
|
||||
std::vector<crypto::hash> hashes{};
|
||||
if (!c.get_pool_transaction_hashes(hashes))
|
||||
{
|
||||
MERROR("Failed to get broadcasted transaction pool hashes");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const crypto::hash& hash : hashes)
|
||||
m_broadcasted_hashes.insert(hash);
|
||||
|
||||
if (new_broadcasted_hash_count != m_broadcasted_hashes.size())
|
||||
{
|
||||
MERROR("Expected " << new_broadcasted_hash_count << " broadcasted hashes but got " << m_broadcasted_hashes.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_broadcasted_hashes.size() != c.get_pool_transactions_count())
|
||||
{
|
||||
MERROR("Expected " << m_broadcasted_hashes.size() << " broadcasted hashes but got " << c.get_pool_transactions_count());
|
||||
return false;
|
||||
}
|
||||
|
||||
hashes.clear();
|
||||
if (!c.get_pool_transaction_hashes(hashes, false))
|
||||
{
|
||||
MERROR("Failed to get broadcasted transaction pool hashes");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const crypto::hash& hash : hashes)
|
||||
m_all_hashes.insert(std::make_pair(hash, 0));
|
||||
|
||||
if (new_broadcasted_hash_count != m_broadcasted_hashes.size())
|
||||
{
|
||||
MERROR("Expected " << new_broadcasted_hash_count << " broadcasted hashes but got " << m_broadcasted_hashes.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
hashes.clear();
|
||||
if (!c.get_pool_transaction_hashes(hashes, true))
|
||||
{
|
||||
|
||||
MERROR("Failed to get all transaction pool hashes");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const crypto::hash& hash : hashes)
|
||||
m_all_hashes.insert(std::make_pair(hash, 0));
|
||||
|
||||
if (new_all_hash_count != m_all_hashes.size())
|
||||
{
|
||||
MERROR("Expected " << new_all_hash_count << " all hashes but got " << m_all_hashes.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition == relay_test::no_relay)
|
||||
{
|
||||
if (!m_no_relay_hashes.insert(m_last_tx).second)
|
||||
{
|
||||
MERROR("Expected new no_relay tx but got a duplicate legacy tx");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const crypto::hash& hash : m_no_relay_hashes)
|
||||
{
|
||||
if (!c.pool_has_tx(hash))
|
||||
{
|
||||
MERROR("Expected public tx " << hash << " to be listed in pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check receive time changes
|
||||
{
|
||||
std::vector<cryptonote::tx_info> infos{};
|
||||
std::vector<cryptonote::spent_key_image_info> key_images{};
|
||||
if (!c.get_pool_transactions_and_spent_keys_info(infos, key_images, true) || infos.size() != m_all_hashes.size())
|
||||
{
|
||||
MERROR("Unable to retrieve all txpool metadata");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const cryptonote::tx_info& info : infos)
|
||||
{
|
||||
crypto::hash tx_hash;
|
||||
if (!epee::string_tools::hex_to_pod(info.id_hash, tx_hash))
|
||||
{
|
||||
MERROR("Unable to convert tx_hash hex to binary");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto entry = m_all_hashes.find(tx_hash);
|
||||
if (entry == m_all_hashes.end())
|
||||
{
|
||||
MERROR("Unable to find tx_hash in set of tracked hashes");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_new_timestamp_index == ev_index && m_last_tx == tx_hash)
|
||||
{
|
||||
if (entry->second >= info.receive_time)
|
||||
{
|
||||
MERROR("Last relay time did not change as expected - last at " << entry->second << " and current at " << info.receive_time);
|
||||
return false;
|
||||
}
|
||||
entry->second = info.receive_time;
|
||||
}
|
||||
else if (entry->second != info.receive_time)
|
||||
{
|
||||
MERROR("Last relayed time changed unexpectedly from " << entry->second << " to " << info.receive_time);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<cryptonote::transaction> txes{};
|
||||
if (!c.get_pool_transactions(txes))
|
||||
{
|
||||
MERROR("Failed to get broadcasted transactions from pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
hashes.clear();
|
||||
for (const cryptonote::transaction& tx : txes)
|
||||
hashes.push_back(cryptonote::get_transaction_hash(tx));
|
||||
|
||||
std::unordered_set<crypto::hash> public_hashes = m_broadcasted_hashes;
|
||||
for (const crypto::hash& hash : hashes)
|
||||
{
|
||||
if (!c.pool_has_tx(hash))
|
||||
{
|
||||
MERROR("Expected broadcasted tx " << hash << " to be listed in pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!public_hashes.erase(hash))
|
||||
{
|
||||
MERROR("An unexected transaction was returned from the public pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!public_hashes.empty())
|
||||
{
|
||||
MERROR(public_hashes.size() << " transaction(s) were missing from the public pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<cryptonote::transaction> txes{};
|
||||
if (!c.get_pool_transactions(txes, false))
|
||||
{
|
||||
MERROR("Failed to get broadcasted transactions from pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
hashes.clear();
|
||||
for (const cryptonote::transaction& tx : txes)
|
||||
hashes.push_back(cryptonote::get_transaction_hash(tx));
|
||||
|
||||
std::unordered_set<crypto::hash> public_hashes = m_broadcasted_hashes;
|
||||
for (const crypto::hash& hash : hashes)
|
||||
{
|
||||
|
||||
if (!public_hashes.erase(hash))
|
||||
{
|
||||
MERROR("An unexected transaction was returned from the public pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!public_hashes.empty())
|
||||
{
|
||||
MERROR(public_hashes.size() << " transaction(s) were missing from the public pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<cryptonote::transaction> txes{};
|
||||
if (!c.get_pool_transactions(txes, true))
|
||||
{
|
||||
MERROR("Failed to get all transactions from pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
hashes.clear();
|
||||
for (const cryptonote::transaction& tx : txes)
|
||||
hashes.push_back(cryptonote::get_transaction_hash(tx));
|
||||
|
||||
std::unordered_map<crypto::hash, uint64_t> all_hashes = m_all_hashes;
|
||||
for (const crypto::hash& hash : hashes)
|
||||
{
|
||||
if (!all_hashes.erase(hash))
|
||||
{
|
||||
MERROR("An unexected transaction was returned from the all pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!all_hashes.empty())
|
||||
{
|
||||
MERROR(m_broadcasted_hashes.size() << " transaction(s) were missing from the all pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<cryptonote::tx_backlog_entry> entries{};
|
||||
if (!c.get_txpool_backlog(entries))
|
||||
{
|
||||
MERROR("Failed to get broadcasted txpool backlog");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_broadcasted_hashes.size() != entries.size())
|
||||
{
|
||||
MERROR("Expected " << m_broadcasted_hashes.size() << " in the broadcasted txpool backlog but got " << entries.size());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::pair<crypto::hash, uint64_t>& hash : m_all_hashes)
|
||||
{
|
||||
cryptonote::blobdata tx_blob{};
|
||||
if (!c.get_pool_transaction(hash.first, tx_blob, cryptonote::relay_category::all))
|
||||
{
|
||||
MERROR("Failed to retrieve tx expected to be in pool: " << hash.first);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::unordered_map<crypto::hash, uint64_t> difference = m_all_hashes;
|
||||
for (const crypto::hash& hash : m_broadcasted_hashes)
|
||||
difference.erase(hash);
|
||||
|
||||
for (const crypto::hash& hash : m_no_relay_hashes)
|
||||
difference.erase(hash);
|
||||
|
||||
for (const std::pair<crypto::hash, uint64_t>& hash : difference)
|
||||
{
|
||||
if (c.pool_has_tx(hash.first))
|
||||
{
|
||||
MERROR("Did not expect private/hidden tx " << hash.first << " to be listed in pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
cryptonote::blobdata tx_blob{};
|
||||
if (c.get_pool_transaction(hash.first, tx_blob, cryptonote::relay_category::broadcasted))
|
||||
{
|
||||
MERROR("Tx " << hash.first << " is not supposed to be in broadcasted pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!c.get_pool_transaction(hash.first, tx_blob, cryptonote::relay_category::all))
|
||||
{
|
||||
MERROR("Tx " << hash.first << " blob could not be retrieved from pool");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
cryptonote::txpool_stats stats{};
|
||||
if (!c.get_pool_transaction_stats(stats) || stats.txs_total != m_broadcasted_hashes.size())
|
||||
{
|
||||
MERROR("Expected broadcasted stats to list " << m_broadcasted_hashes.size() << " txes but got " << stats.txs_total);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!c.get_pool_transaction_stats(stats, false) || stats.txs_total != m_broadcasted_hashes.size())
|
||||
{
|
||||
MERROR("Expected broadcasted stats to list " << m_broadcasted_hashes.size() << " txes but got " << stats.txs_total);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!c.get_pool_transaction_stats(stats, true) || stats.txs_total != m_all_hashes.size())
|
||||
{
|
||||
MERROR("Expected all stats to list " << m_all_hashes.size() << " txes but got " << stats.txs_total);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<cryptonote::rpc::tx_in_pool> infos{};
|
||||
cryptonote::rpc::key_images_with_tx_hashes key_images{};
|
||||
if (!c.get_pool_for_rpc(infos, key_images) || infos.size() != m_broadcasted_hashes.size() || key_images.size() != m_broadcasted_hashes.size())
|
||||
{
|
||||
MERROR("Expected broadcasted rpc data to return " << m_broadcasted_hashes.size() << " but got " << infos.size() << " infos and " << key_images.size() << "key images");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::check_unchanged(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& /*events */)
|
||||
{
|
||||
return check_changed(c, ev_index, relay_test::no_change);
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::check_new_broadcasted(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& /*events */)
|
||||
{
|
||||
return check_changed(c, ev_index, relay_test::broadcasted);
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::check_new_hidden(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& /*events */)
|
||||
{
|
||||
return check_changed(c, ev_index, relay_test::hidden);
|
||||
}
|
||||
bool txpool_double_spend_base::check_new_no_relay(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& /*events */)
|
||||
{
|
||||
return check_changed(c, ev_index, relay_test::no_relay);
|
||||
}
|
||||
|
||||
bool txpool_double_spend_base::check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& tx)
|
||||
{
|
||||
m_last_tx = cryptonote::get_transaction_hash(tx);
|
||||
if (m_no_new_index == event_idx)
|
||||
return !tvc.m_verifivation_failed && !tx_added;
|
||||
else
|
||||
return !tvc.m_verifivation_failed && tx_added;
|
||||
}
|
||||
|
||||
bool txpool_double_spend_norelay::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
INIT_MEMPOOL_TEST();
|
||||
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_do_not_relay);
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
|
||||
MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
|
||||
|
||||
DO_CALLBACK(events, "increase_all_tx_count");
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "mark_timestamp_change");
|
||||
DO_CALLBACK(events, "check_new_no_relay");
|
||||
DO_CALLBACK(events, "timestamp_change_pause");
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
events.push_back(tx_0);
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "check_unchanged");
|
||||
SET_EVENT_VISITOR_SETT(events, 0);
|
||||
DO_CALLBACK(events, "timestamp_change_pause");
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
events.push_back(tx_0);
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "check_unchanged");
|
||||
|
||||
// kepped by block currently does not change txpool status
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block);
|
||||
DO_CALLBACK(events, "timestamp_change_pause");
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
events.push_back(tx_0);
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "check_unchanged");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool txpool_double_spend_local::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
INIT_MEMPOOL_TEST();
|
||||
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_local_relay);
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
|
||||
MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
|
||||
|
||||
DO_CALLBACK(events, "increase_all_tx_count");
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "mark_timestamp_change");
|
||||
DO_CALLBACK(events, "check_new_hidden");
|
||||
DO_CALLBACK(events, "timestamp_change_pause");
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
events.push_back(tx_0);
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "mark_timestamp_change");
|
||||
DO_CALLBACK(events, "check_unchanged");
|
||||
SET_EVENT_VISITOR_SETT(events, 0);
|
||||
DO_CALLBACK(events, "timestamp_change_pause");
|
||||
events.push_back(tx_0);
|
||||
DO_CALLBACK(events, "increase_broadcasted_tx_count");
|
||||
DO_CALLBACK(events, "check_txpool_spent_keys");
|
||||
DO_CALLBACK(events, "mark_timestamp_change");
|
||||
DO_CALLBACK(events, "check_new_broadcasted");
|
||||
DO_CALLBACK(events, "timestamp_change_pause");
|
||||
DO_CALLBACK(events, "mark_no_new");
|
||||
events.push_back(tx_0);
|
||||
DO_CALLBACK(events, "check_unchanged");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
118
tests/core_tests/tx_pool.h
Normal file
118
tests/core_tests/tx_pool.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2019, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
enum class relay_test
|
||||
{
|
||||
no_change = 0, //!< No expected changes to the txpool
|
||||
broadcasted, //!< A new block or fluff/flood tx is expected in txpool
|
||||
hidden, //!< A new stem or local tx is expected in txpool
|
||||
no_relay //!< A new no relay is expected in txpool
|
||||
};
|
||||
|
||||
class txpool_base : public test_chain_unit_base
|
||||
{
|
||||
size_t m_broadcasted_tx_count;
|
||||
size_t m_all_tx_count;
|
||||
|
||||
public:
|
||||
txpool_base();
|
||||
|
||||
bool increase_broadcasted_tx_count(cryptonote::core& c, size_t /*ev_index*/, const std::vector<test_event_entry>& events);
|
||||
bool increase_all_tx_count(cryptonote::core& c, size_t /*ev_index*/, const std::vector<test_event_entry>& events);
|
||||
bool check_txpool_spent_keys(cryptonote::core& c, size_t /*ev_index*/, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
struct txpool_spend_key_public : txpool_base
|
||||
{
|
||||
txpool_spend_key_public() : txpool_base()
|
||||
{}
|
||||
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct txpool_spend_key_all : txpool_base
|
||||
{
|
||||
txpool_spend_key_all() : txpool_base()
|
||||
{}
|
||||
|
||||
bool generate(std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
class txpool_double_spend_base : public txpool_base
|
||||
{
|
||||
std::unordered_set<crypto::hash> m_broadcasted_hashes;
|
||||
std::unordered_set<crypto::hash> m_no_relay_hashes;
|
||||
std::unordered_map<crypto::hash, uint64_t> m_all_hashes;
|
||||
size_t m_no_new_index;
|
||||
size_t m_new_timestamp_index;
|
||||
crypto::hash m_last_tx;
|
||||
|
||||
bool check_changed(cryptonote::core& c, size_t ev_index, relay_test condition);
|
||||
|
||||
public:
|
||||
txpool_double_spend_base();
|
||||
|
||||
bool mark_no_new(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool mark_timestamp_change(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
//! Pause for 1 second, so that `receive_time` for tx meta changes (tx hidden from public rpc being updated)
|
||||
bool timestamp_change_pause(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
bool check_unchanged(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_new_broadcasted(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_new_hidden(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_new_no_relay(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/);
|
||||
};
|
||||
|
||||
struct txpool_double_spend_norelay : txpool_double_spend_base
|
||||
{
|
||||
txpool_double_spend_norelay()
|
||||
: txpool_double_spend_base()
|
||||
{}
|
||||
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct txpool_double_spend_local : txpool_double_spend_base
|
||||
{
|
||||
txpool_double_spend_local()
|
||||
: txpool_double_spend_base()
|
||||
{}
|
||||
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
|
@ -32,6 +32,7 @@
|
|||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "p2p/net_node.inl"
|
||||
#include "cryptonote_core/i_core_events.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.inl"
|
||||
|
||||
|
@ -43,7 +44,7 @@ namespace cryptonote {
|
|||
class blockchain_storage;
|
||||
}
|
||||
|
||||
class test_core
|
||||
class test_core : public cryptonote::i_core_events
|
||||
{
|
||||
public:
|
||||
void on_synchronized(){}
|
||||
|
@ -56,8 +57,8 @@ public:
|
|||
bool get_stat_info(cryptonote::core_stat_info& st_inf) const {return true;}
|
||||
bool have_block(const crypto::hash& id) const {return true;}
|
||||
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}
|
||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
|
||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
|
||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
||||
bool handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true) { return true; }
|
||||
void pause_mine(){}
|
||||
void resume_mine(){}
|
||||
|
@ -71,9 +72,9 @@ public:
|
|||
bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; }
|
||||
uint64_t get_target_blockchain_height() const { return 1; }
|
||||
size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; }
|
||||
virtual void on_transaction_relayed(const cryptonote::blobdata& tx) {}
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, cryptonote::relay_method tx_relay) {}
|
||||
cryptonote::network_type get_nettype() const { return cryptonote::MAINNET; }
|
||||
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob) const { return false; }
|
||||
bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx_blob, cryptonote::relay_category tx_category) const { return false; }
|
||||
bool pool_has_tx(const crypto::hash &txid) const { return false; }
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::vector<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::vector<cryptonote::blobdata>& txs) const { return false; }
|
||||
bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::vector<cryptonote::transaction>& txs, std::vector<crypto::hash>& missed_txs) const { return false; }
|
||||
|
|
Loading…
Reference in a new issue