Electroneum
cryptonote::tx_memory_pool Class Reference

Transaction pool, handles transactions which are not part of a block. More...

#include <tx_pool.h>

Inheritance diagram for cryptonote::tx_memory_pool:
Collaboration diagram for cryptonote::tx_memory_pool:

Classes

struct  tx_details
 information about a single transaction More...
 

Public Member Functions

 tx_memory_pool (Blockchain &bchs)
 Constructor. More...
 
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, tx_verification_context &tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
 add a transaction to the transaction pool More...
 
bool take_tx (const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t &tx_weight, uint64_t &fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen, bool &nonexistent_utxo_seen)
 takes a transaction with the given hash from the pool More...
 
bool have_tx (const crypto::hash &id) const
 checks if the pool has a transaction with the given hash More...
 
bool on_blockchain_inc (uint64_t new_block_height, const crypto::hash &top_block_id)
 action to take when notified of a block added to the blockchain More...
 
bool on_blockchain_dec (uint64_t new_block_height, const crypto::hash &top_block_id)
 action to take when notified of a block removed from the blockchain More...
 
void on_idle ()
 action to take periodically More...
 
void lock () const
 locks the transaction pool More...
 
void unlock () const
 unlocks the transaction pool More...
 
bool init (size_t max_txpool_weight=0)
 loads pool state (if any) from disk, and initializes pool More...
 
bool deinit ()
 attempts to save the transaction pool state to disk More...
 
bool fill_block_template (block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
 Chooses transactions for a block to include. More...
 
void get_transactions (std::vector< transaction > &txs, bool include_unrelayed_txes=true) const
 get a list of all transactions in the pool More...
 
void get_transaction_hashes (std::vector< crypto::hash > &txs, bool include_unrelayed_txes=true) const
 get a list of all transaction hashes in the pool More...
 
void get_transaction_backlog (std::vector< tx_backlog_entry > &backlog, bool include_unrelayed_txes=true) const
 get (weight, fee, receive time) for all transaction in the pool More...
 
void get_transaction_stats (struct txpool_stats &stats, bool include_unrelayed_txes=true) const
 get a summary statistics of all transaction hashes in the pool More...
 
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
 get information about all transactions and key images in the pool More...
 
bool get_pool_for_rpc (std::vector< cryptonote::rpc::tx_in_pool > &tx_infos, cryptonote::rpc::key_images_with_tx_hashes &key_image_infos) const
 get information about all transactions and key images in the pool More...
 
bool check_for_key_images (const std::vector< crypto::key_image > &key_images, std::vector< bool > spent) const
 check for presence of key images in the pool More...
 
bool get_transaction (const crypto::hash &h, cryptonote::blobdata &txblob) const
 get a specific transaction from the pool More...
 
bool get_relayable_transactions (std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs) const
 get a list of all relayable transactions and their hashes More...
 
void set_relayed (const std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs)
 tell the pool that certain transactions were just relayed More...
 
size_t get_transactions_count (bool include_unrelayed_txes=true) const
 get the total number of transactions in the pool More...
 
std::string print_pool (bool short_format) const
 get a string containing human-readable pool information More...
 
size_t validate (uint8_t version)
 remove transactions from the pool which are no longer valid More...
 
uint64_t cookie () const
 return the cookie More...
 
size_t get_txpool_weight () const
 get the cumulative txpool weight in bytes More...
 
void set_txpool_max_weight (size_t bytes)
 set the max cumulative txpool weight in bytes More...
 

Detailed Description

Transaction pool, handles transactions which are not part of a block.

This class handles all transactions which have been received, but not as part of a block.

This handling includes: storing the transactions organizing the transactions by fee per weight unit taking/giving transactions to and from various other components saving the transactions to disk on shutdown helping create a new block template by choosing transactions for it

Definition at line 94 of file tx_pool.h.

Constructor & Destructor Documentation

◆ tx_memory_pool()

cryptonote::tx_memory_pool::tx_memory_pool ( Blockchain bchs)

Constructor.

Parameters
bchsa Blockchain class instance, for getting chain info

Definition at line 115 of file tx_pool.cpp.

115  : m_blockchain(bchs), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_cookie(0)
116  {
117 
118  }
#define DEFAULT_TXPOOL_MAX_WEIGHT

Member Function Documentation

◆ add_tx() [1/2]

bool cryptonote::tx_memory_pool::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 
)

Parameters
idthe transaction's hash
tx_weightthe transaction's weight

Definition at line 120 of file tx_pool.cpp.

121  {
122  // this should already be called with that lock, but let's make it explicit for clarity
123  CRITICAL_REGION_LOCAL(m_transactions_lock);
124 
126  if (tx.version == 0)
127  {
128  // v0 never accepted
129  LOG_PRINT_L1("transaction version 0 is invalid");
130  tvc.m_verification_failed = true;
131  return false;
132  }
133 
134  // we do not accept transactions that timed out before, unless they're
135  // kept_by_block
136  if (!kept_by_block && m_timed_out_transactions.find(id) != m_timed_out_transactions.end())
137  {
138  // not clear if we should set that, since verifivation (sic) did not fail before, since
139  // the tx was accepted before timing out.
140  tvc.m_verification_failed = true;
141  return false;
142  }
143 
145  {
146  tvc.m_verification_failed = true;
147  tvc.m_invalid_input = true;
148  return false;
149  }
150 
151  if(!check_outs_valid(tx))
152  {
153  tvc.m_verification_failed = true;
154  tvc.m_invalid_output = true;
155  return false;
156  }
157 
158  // fee per kilobyte, size rounded up.
159  uint64_t fee = 0;
160 
161  uint64_t inputs_amount = 0;
162  if(!get_inputs_etn_amount(tx, inputs_amount))
163  {
164  tvc.m_verification_failed = true;
165  return false;
166  }
167 
168  uint64_t outputs_amount = get_outs_etn_amount(tx);
169  if(outputs_amount > inputs_amount)
170  {
171  LOG_PRINT_L1("transaction use more ETN than it has: use " << print_etn(outputs_amount) << ", have " << print_etn(inputs_amount));
172  tvc.m_verification_failed = true;
173  tvc.m_overspend = true;
174  return false;
175  }
176  else if(tx.version != 2 && outputs_amount == inputs_amount)
177  {
178  LOG_PRINT_L1("transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
179  tvc.m_verification_failed = true;
180  tvc.m_fee_too_low = true;
181  return false;
182  }
183 
184  fee = inputs_amount - outputs_amount;
185 
186  if(tx.version == 2 && fee != 0) //Assure 0 fee tx v2 (migration tx)
187  {
188  LOG_PRINT_L1("transaction v2 fee is greater than zero, rejecting.");
189  tvc.m_verification_failed = true;
190  return false;
191  }
192 
193  if (tx.version != 2 && !kept_by_block && !m_blockchain.check_fee(tx_weight, fee))
194  {
195  tvc.m_verification_failed = true;
196  tvc.m_fee_too_low = true;
197  return false;
198  }
199 
200  size_t tx_weight_limit = get_transaction_weight_limit(version);
201  if ((!kept_by_block || version >= HF_VERSION_PER_BYTE_FEE) && tx_weight > tx_weight_limit)
202  {
203  LOG_PRINT_L1("transaction is too heavy: " << tx_weight << " bytes, maximum weight: " << tx_weight_limit);
204  tvc.m_verification_failed = true;
205  tvc.m_too_big = true;
206  return false;
207  }
208 
209  // if the transaction came from a block popped from the chain,
210  // don't check if we have its key images as spent.
211  // TODO: Investigate why not?
212  if(!kept_by_block)
213  {
214  if(tx.version <= 2) {
215  if (key_images_already_spent(tx)) {
216  mark_double_spend_or_nonexistent_utxo(tx);
217  LOG_PRINT_L1("Transaction with id= " << id << " used already spent key images");
218  tvc.m_verification_failed = true;
219  tvc.m_double_spend = true;
220  return false;
221  }
222  }
223  if(tx.version > 2) {
224  if (utxo_nonexistent(tx)) {
225  mark_double_spend_or_nonexistent_utxo(tx);
226  LOG_PRINT_L1("Transaction with id= " << id << " used nonexistent utxos");
227  tvc.m_verification_failed = true;
228  tvc.m_utxo_nonexistent = true;
229  return false;
230  }
231  }
232  }
233 
234  if (!m_blockchain.check_tx_outputs(tx, tvc))
235  {
236  LOG_PRINT_L1("Transaction with id= "<< id << " has at least one invalid output");
237  tvc.m_verification_failed = true;
238  tvc.m_invalid_output = true;
239  return false;
240  }
241 
242  // assume failure during verification steps until success is certain
243  tvc.m_verification_failed = true;
244 
245  time_t receive_time = time(nullptr);
246 
247  crypto::hash max_used_block_id = null_hash;
248  uint64_t max_used_block_height = 0;
250  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);
251  if(!ch_inp_res)
252  {
253  // if the transaction was valid before (kept_by_block), then it
254  // may become valid again, so ignore the failed inputs check.
255  if(kept_by_block)
256  {
257  meta.weight = tx_weight;
258  meta.fee = fee;
259  meta.max_used_block_id = null_hash;
260  meta.max_used_block_height = 0;
261  meta.last_failed_height = 0;
262  meta.last_failed_id = null_hash;
263  meta.kept_by_block = kept_by_block;
264  meta.receive_time = receive_time;
265  meta.last_relayed_time = time(NULL);
266  meta.relayed = relayed;
267  meta.do_not_relay = do_not_relay;
268  meta.double_spend_seen = key_images_already_spent(tx);
269  meta.utxo_nonexistent_seen = utxo_nonexistent(tx);
270  meta.bf_padding = 0;
271  memset(meta.padding, 0, sizeof(meta.padding));
272  try
273  {
274  if (kept_by_block)
275  m_parsed_tx_cache.insert(std::make_pair(id, tx));
276  CRITICAL_REGION_LOCAL1(m_blockchain);
277  LockedTXN lock(m_blockchain);
278  m_blockchain.add_txpool_tx(id, blob, meta);
279  if ((tx.version <= 2 && !insert_key_images(tx, id, kept_by_block)) || (tx.version >= 3 && !insert_utxos(tx, id, kept_by_block)))
280  return false;
281  m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
282  lock.commit();
283  }
284  catch (const std::exception &e)
285  {
286  MERROR("transaction already exists at inserting in memory pool: " << e.what());
287  return false;
288  }
289  tvc.m_verification_impossible = true;
290  tvc.m_added_to_pool = true;
291  }else
292  {
293  LOG_PRINT_L1("tx used wrong inputs, rejected");
294  tvc.m_verification_failed = true;
295  tvc.m_invalid_input = true;
296  return false;
297  }
298  }else
299  {
300  //update transactions container
301  meta.weight = tx_weight;
302  meta.kept_by_block = kept_by_block;
303  meta.fee = fee;
304  meta.max_used_block_id = max_used_block_id;
305  meta.max_used_block_height = max_used_block_height;
306  meta.last_failed_height = 0;
307  meta.last_failed_id = null_hash;
308  meta.receive_time = receive_time;
309  meta.last_relayed_time = time(NULL);
310  meta.relayed = relayed;
311  meta.do_not_relay = do_not_relay;
312  meta.double_spend_seen = false;
313  meta.utxo_nonexistent_seen = false;
314  meta.bf_padding = 0;
315  memset(meta.padding, 0, sizeof(meta.padding));
316 
317  try
318  {
319  if (kept_by_block)
320  m_parsed_tx_cache.insert(std::make_pair(id, tx));
321  CRITICAL_REGION_LOCAL1(m_blockchain);
322  LockedTXN lock(m_blockchain);
323  m_blockchain.remove_txpool_tx(id);
324  m_blockchain.add_txpool_tx(id, blob, meta);
325  if ((tx.version <= 2 && !insert_key_images(tx, id, kept_by_block)) || (tx.version >= 3 && !insert_utxos(tx, id, kept_by_block)))
326  return false;
327  m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
328  lock.commit();
329  }
330  catch (const std::exception &e)
331  {
332  MERROR("internal error: transaction already exists at inserting in memory pool: " << e.what());
333  return false;
334  }
335  tvc.m_added_to_pool = true;
336 
337  if(!do_not_relay)
338  tvc.m_should_be_relayed = true;
339  }
340 
341  tvc.m_verification_failed = false;
342  m_txpool_weight += tx_weight;
343 
344  ++m_cookie;
345 
346  MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)tx_weight));
347 
348  prune(m_txpool_max_weight);
349 
350  return true;
351  }
time_t time
Definition: blockchain.cpp:93
bool check_fee(size_t tx_weight, uint64_t fee) const
validate a transaction's fee
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta)
bool check_tx_outputs(const transaction &tx, tx_verification_context &tvc)
check that a transaction's outputs conform to current standards
void remove_txpool_tx(const crypto::hash &txid)
void lock() const
locks the transaction pool
Definition: tx_pool.cpp:1078
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)
Definition: tx_pool.cpp:120
#define HF_VERSION_PER_BYTE_FEE
#define MERROR(x)
Definition: misc_log_ex.h:73
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
#define MINFO(x)
Definition: misc_log_ex.h:75
POD_CLASS hash
Definition: hash.h:50
uint64_t get_outs_etn_amount(const transaction &tx)
bool check_outs_valid(const transaction &tx)
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
bool check_inputs_types_supported(const transaction &tx)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
version
Supported socks variants.
Definition: socks.h:58
#define PERF_TIMER(name)
Definition: perf_timer.h:82
unsigned __int64 uint64_t
Definition: stdint.h:136
a struct containing txpool per transaction metadata
#define CRITICAL_REGION_LOCAL1(x)
Definition: syncobj.h:230
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
Here is the call graph for this function:

◆ add_tx() [2/2]

bool cryptonote::tx_memory_pool::add_tx ( transaction tx,
tx_verification_context tvc,
bool  kept_by_block,
bool  relayed,
bool  do_not_relay,
uint8_t  version 
)

add a transaction to the transaction pool

Most likely the transaction will come from the network, but it is also possible for transactions to come from popped blocks during a reorg, or from local clients creating a transaction and submitting it to the network

Parameters
txthe transaction to be added
tvcreturn-by-reference status about the transaction verification
kept_by_blockhas this transaction been in a block?
relayedwas this transaction from the network or a local client?
do_not_relayto avoid relaying the transaction to the network
versionthe version used to create the transaction
Returns
true if the transaction passes validations, otherwise false

Definition at line 353 of file tx_pool.cpp.

354  {
355  crypto::hash h = null_hash;
356  size_t blob_size = 0;
359  if (bl.size() == 0 || !get_transaction_hash(tx, h))
360  return false;
361  return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, keeped_by_block, relayed, do_not_relay, version);
362  }
crypto::hash get_transaction_hash(const transaction &t)
std::string blobdata
Definition: blobdatatype.h:39
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)

◆ check_for_key_images()

bool cryptonote::tx_memory_pool::check_for_key_images ( const std::vector< crypto::key_image > &  key_images,
std::vector< bool spent 
) const

check for presence of key images in the pool

Parameters
key_images[in] vector of key images to check
spent[out] vector of bool to return
Returns
true

Definition at line 980 of file tx_pool.cpp.

981  {
982  CRITICAL_REGION_LOCAL(m_transactions_lock);
983  CRITICAL_REGION_LOCAL1(m_blockchain);
984 
985  spent.clear();
986 
987  for (const auto& image : key_images)
988  {
989  spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ? false : true);
990  }
991 
992  return true;
993  }
Here is the caller graph for this function:

◆ cookie()

uint64_t cryptonote::tx_memory_pool::cookie ( ) const
inline

return the cookie

Returns
the cookie

Definition at line 373 of file tx_pool.h.

373 { return m_cookie; }
Here is the caller graph for this function:

◆ deinit()

bool cryptonote::tx_memory_pool::deinit ( )

attempts to save the transaction pool state to disk

Currently fails (returns false) if the data directory from init() does not exist and cannot be created, but returns true even if saving to disk is unsuccessful.

Returns
true in most cases (see above)

Definition at line 1623 of file tx_pool.cpp.

1624  {
1625  return true;
1626  }
Here is the caller graph for this function:

◆ fill_block_template()

bool cryptonote::tx_memory_pool::fill_block_template ( block bl,
size_t  median_weight,
uint64_t  already_generated_coins,
size_t &  total_weight,
uint64_t fee,
uint64_t expected_reward,
uint8_t  version 
)

Chooses transactions for a block to include.

Parameters
blreturn-by-reference the block to fill in with transactions
median_weightthe current median block weight
already_generated_coinsthe current total number of coins "minted"
total_weightreturn-by-reference the total weight of the new block
feereturn-by-reference the total of fees from the included transactions
expected_rewardreturn-by-reference the total reward awarded to the miner finding this block, including transaction fees
versionhard fork version to use for consensus rules
Returns
true

Definition at line 1358 of file tx_pool.cpp.

1359  {
1360  CRITICAL_REGION_LOCAL(m_transactions_lock);
1361  CRITICAL_REGION_LOCAL1(m_blockchain);
1362 
1363  uint64_t best_coinbase = 0, coinbase = 0;
1364  total_weight = 0;
1365  fee = 0;
1366 
1367  //baseline empty block
1368  get_block_reward(median_weight, total_weight, already_generated_coins, best_coinbase, version, m_blockchain.get_current_blockchain_height(), m_blockchain.get_nettype());
1369 
1370 
1371  size_t max_total_weight_pre_v5 = (130 * median_weight) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
1372  size_t max_total_weight_v5 = 2 * median_weight - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
1373  size_t max_total_weight = version >= 5 ? max_total_weight_v5 : max_total_weight_pre_v5;
1374  std::unordered_set<crypto::key_image> k_images;
1375  std::unordered_set<std::string> utxos;
1376 
1377  LOG_PRINT_L2("Filling block template, median weight " << median_weight << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
1378 
1379  LockedTXN lock(m_blockchain);
1380 
1381  auto sorted_it = m_txs_by_fee_and_receive_time.begin();
1382  for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
1383  {
1384  txpool_tx_meta_t meta;
1385  if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
1386  {
1387  MERROR(" failed to find tx meta");
1388  continue;
1389  }
1390  LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_etn(best_coinbase));
1391 
1392  // Can not exceed maximum block weight
1393  if (max_total_weight < total_weight + meta.weight)
1394  {
1395  LOG_PRINT_L2(" would exceed maximum block weight");
1396  continue;
1397  }
1398 
1399  // start using the optimal filling algorithm from v5
1400  if (version >= 5)
1401  {
1402  // If we're getting lower coinbase tx,
1403  // stop including more tx
1404  uint64_t block_reward;
1405  if(!get_block_reward(median_weight, total_weight + meta.weight, already_generated_coins, block_reward, version, m_blockchain.get_current_blockchain_height(), m_blockchain.get_nettype()))
1406  {
1407  LOG_PRINT_L2(" would exceed maximum block weight");
1408  continue;
1409  }
1410  coinbase = block_reward + fee + meta.fee;
1411  if (coinbase < template_accept_threshold(best_coinbase))
1412  {
1413  LOG_PRINT_L2(" would decrease coinbase to " << print_etn(coinbase));
1414  continue;
1415  }
1416  }
1417  else
1418  {
1419  // If we've exceeded the penalty free weight,
1420  // stop including more tx
1421  if (total_weight > median_weight)
1422  {
1423  LOG_PRINT_L2(" would exceed median block weight");
1424  break;
1425  }
1426  }
1427 
1428  cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second);
1430 
1431  // Skip transactions that are not ready to be
1432  // included into the blockchain or that are
1433  // missing key images
1434  const cryptonote::txpool_tx_meta_t original_meta = meta;
1435  bool ready = false;
1436  try
1437  {
1438  ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
1439  }
1440  catch (const std::exception &e)
1441  {
1442  MERROR("Failed to check transaction readiness: " << e.what());
1443  // continue, not fatal
1444  }
1445  if (memcmp(&original_meta, &meta, sizeof(meta)))
1446  {
1447  try
1448  {
1449  m_blockchain.update_txpool_tx(sorted_it->second, meta);
1450  }
1451  catch (const std::exception &e)
1452  {
1453  MERROR("Failed to update tx meta: " << e.what());
1454  // continue, not fatal
1455  }
1456  }
1457  if (!ready)
1458  {
1459  LOG_PRINT_L2(" not ready to go");
1460  continue;
1461  }
1462  if (have_key_images(k_images, tx))
1463  {
1464  LOG_PRINT_L2(" key images already seen");
1465  continue;
1466  }
1467  if (have_utxos(utxos, tx))
1468  {
1469  LOG_PRINT_L2(" utxos already seen");
1470  continue;
1471  }
1472 
1473  bl.tx_hashes.push_back(sorted_it->second);
1474  total_weight += meta.weight;
1475  fee += meta.fee;
1476  best_coinbase = coinbase;
1477  append_key_images(k_images, tx);
1478  append_utxos(utxos, tx);
1479  LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_etn(best_coinbase));
1480  }
1481  lock.commit();
1482 
1483  expected_reward = best_coinbase;
1484  LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight "
1485  << total_weight << "/" << max_total_weight << ", coinbase " << print_etn(best_coinbase)
1486  << " (including " << print_etn(fee) << " in fees)");
1487  return true;
1488  }
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta)
network_type get_nettype() const
get blockchain nettype
Definition: blockchain.h:1048
bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
Definition: blockchain.cpp:319
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version, uint64_t current_block_height, network_type nettype)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_pool_for_rpc()

bool cryptonote::tx_memory_pool::get_pool_for_rpc ( std::vector< cryptonote::rpc::tx_in_pool > &  tx_infos,
cryptonote::rpc::key_images_with_tx_hashes key_image_infos 
) const

get information about all transactions and key images in the pool

see documentation on tx_in_pool and key_images_with_tx_hashes for more details

Parameters
tx_infos[out] the transactions' information
key_image_infos[out] the spent key images' information
Returns
true

Definition at line 931 of file tx_pool.cpp.

932  {
933  CRITICAL_REGION_LOCAL(m_transactions_lock);
934  CRITICAL_REGION_LOCAL1(m_blockchain);
935  tx_infos.reserve(m_blockchain.get_txpool_tx_count());
936  key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
937  m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
939  txi.tx_hash = txid;
940  if (!parse_and_validate_tx_from_blob(*bd, txi.tx))
941  {
942  MERROR("Failed to parse tx from txpool");
943  // continue
944  return true;
945  }
946  txi.tx.set_hash(txid);
947  txi.blob_size = bd->size();
948  txi.weight = meta.weight;
949  txi.fee = meta.fee;
950  txi.kept_by_block = meta.kept_by_block;
951  txi.max_used_block_height = meta.max_used_block_height;
952  txi.max_used_block_hash = meta.max_used_block_id;
953  txi.last_failed_block_height = meta.last_failed_height;
954  txi.last_failed_block_hash = meta.last_failed_id;
955  txi.receive_time = meta.receive_time;
956  txi.relayed = meta.relayed;
957  txi.last_relayed_time = meta.last_relayed_time;
958  txi.do_not_relay = meta.do_not_relay;
959  txi.double_spend_seen = meta.double_spend_seen;
960  txi.nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
961 
962  tx_infos.push_back(txi);
963  return true;
964  }, true, false);
965 
966  for (const key_images_container::value_type& kee : m_spent_key_images) {
967  std::vector<crypto::hash> tx_hashes;
968  const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
969  for (const crypto::hash& tx_id_hash : kei_image_set)
970  {
971  tx_hashes.push_back(tx_id_hash);
972  }
973 
974  const crypto::key_image& k_image = kee.first;
975  key_image_infos[k_image] = std::move(tx_hashes);
976  }
977  return true;
978  }
uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) 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
void set_hash(const crypto::hash &h)
POD_CLASS key_image
Definition: crypto.h:102
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
const T & move(const T &t)
Definition: gtest-port.h:1317
cryptonote::transaction tx
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_relayable_transactions()

bool cryptonote::tx_memory_pool::get_relayable_transactions ( std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &  txs) const

get a list of all relayable transactions and their hashes

"relayable" in this case means: nonzero fee hasn't been relayed too recently isn't old enough that relaying it is considered harmful Note a transaction can be "relayable" even if do_not_relay is true

Parameters
txsreturn-by-reference the transactions and their hashes
Returns
true

Definition at line 665 of file tx_pool.cpp.

666  {
667  CRITICAL_REGION_LOCAL(m_transactions_lock);
668  CRITICAL_REGION_LOCAL1(m_blockchain);
669  const uint64_t now = time(NULL);
670  txs.reserve(m_blockchain.get_txpool_tx_count());
671  m_blockchain.for_all_txpool_txes([this, now, &txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
672  // 0 fee transactions are never relayed
673  if(!meta.do_not_relay && now - meta.last_relayed_time > get_relay_delay(now, meta.receive_time))
674  {
675  // if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
676  // mentioned by smooth where nodes would flush txes at slightly different times, causing
677  // flushed txes to be re-added when received from a node which was just about to flush it
678  uint32_t mempool_lifetime = m_blockchain.get_mempool_tx_livetime();
679  uint64_t max_age = meta.kept_by_block ? CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME : mempool_lifetime;
680  if (now - meta.receive_time <= max_age / 2)
681  {
682  try
683  {
684  cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
685  txs.push_back(std::make_pair(txid, bd));
686  }
687  catch (const std::exception &e)
688  {
689  MERROR("Failed to get transaction blob from db");
690  // ignore error
691  }
692  }
693  }
694  return true;
695  }, false);
696  return true;
697  }
Here is the call graph for this function:

◆ get_transaction()

bool cryptonote::tx_memory_pool::get_transaction ( const crypto::hash h,
cryptonote::blobdata txblob 
) const

get a specific transaction from the pool

Parameters
hthe hash of the transaction to get
txreturn-by-reference the transaction blob requested
Returns
true if the transaction is found, otherwise false

Definition at line 995 of file tx_pool.cpp.

996  {
997  CRITICAL_REGION_LOCAL(m_transactions_lock);
998  CRITICAL_REGION_LOCAL1(m_blockchain);
999  try
1000  {
1001  return m_blockchain.get_txpool_tx_blob(id, txblob);
1002  }
1003  catch (const std::exception &e)
1004  {
1005  return false;
1006  }
1007  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transaction_backlog()

void cryptonote::tx_memory_pool::get_transaction_backlog ( std::vector< tx_backlog_entry > &  backlog,
bool  include_unrelayed_txes = true 
) const

get (weight, fee, receive time) for all transaction in the pool

Parameters
txsreturn-by-reference that data
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 763 of file tx_pool.cpp.

764  {
765  CRITICAL_REGION_LOCAL(m_transactions_lock);
766  CRITICAL_REGION_LOCAL1(m_blockchain);
767  const uint64_t now = time(NULL);
768  backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
769  m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
770  backlog.push_back({meta.weight, meta.fee, meta.receive_time - now});
771  return true;
772  }, false, include_unrelayed_txes);
773  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transaction_hashes()

void cryptonote::tx_memory_pool::get_transaction_hashes ( std::vector< crypto::hash > &  txs,
bool  include_unrelayed_txes = true 
) const

get a list of all transaction hashes in the pool

Parameters
txsreturn-by-reference the list of transactions
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 752 of file tx_pool.cpp.

753  {
754  CRITICAL_REGION_LOCAL(m_transactions_lock);
755  CRITICAL_REGION_LOCAL1(m_blockchain);
756  txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
757  m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
758  txs.push_back(txid);
759  return true;
760  }, false, include_unrelayed_txes);
761  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transaction_stats()

void cryptonote::tx_memory_pool::get_transaction_stats ( struct txpool_stats stats,
bool  include_unrelayed_txes = true 
) const

get a summary statistics of all transaction hashes in the pool

Parameters
statsreturn-by-reference the pool statistics
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 775 of file tx_pool.cpp.

776  {
777  CRITICAL_REGION_LOCAL(m_transactions_lock);
778  CRITICAL_REGION_LOCAL1(m_blockchain);
779  const uint64_t now = time(NULL);
780  std::map<uint64_t, txpool_histo> agebytes;
781  stats.txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
782  std::vector<uint32_t> weights;
783  weights.reserve(stats.txs_total);
784  m_blockchain.for_all_txpool_txes([&stats, &weights, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
785  weights.push_back(meta.weight);
786  stats.bytes_total += meta.weight;
787  if (!stats.bytes_min || meta.weight < stats.bytes_min)
788  stats.bytes_min = meta.weight;
789  if (meta.weight > stats.bytes_max)
790  stats.bytes_max = meta.weight;
791  if (!meta.relayed)
792  stats.num_not_relayed++;
793  stats.fee_total += meta.fee;
794  if (!stats.oldest || meta.receive_time < stats.oldest)
795  stats.oldest = meta.receive_time;
796  if (meta.receive_time < now - 600)
797  stats.num_10m++;
798  if (meta.last_failed_height)
799  stats.num_failing++;
800  uint64_t age = now - meta.receive_time + (now == meta.receive_time);
801  agebytes[age].txs++;
802  agebytes[age].bytes += meta.weight;
803  if (meta.double_spend_seen)
804  ++stats.num_double_spends;
805  if(meta.utxo_nonexistent_seen)
806  ++stats.num_nonexistent_utxos;
807  return true;
808  }, false, include_unrelayed_txes);
809  stats.bytes_med = epee::misc_utils::median(weights);
810  if (stats.txs_total > 1)
811  {
812  /* looking for 98th percentile */
813  size_t end = stats.txs_total * 0.02;
814  uint64_t delta, factor;
815  std::map<uint64_t, txpool_histo>::iterator it, i2;
816  if (end)
817  {
818  /* If enough txs, spread the first 98% of results across
819  * the first 9 bins, drop final 2% in last bin.
820  */
821  it=agebytes.end();
822  for (size_t n=0; n <= end; n++, it--);
823  stats.histo_98pc = it->first;
824  factor = 9;
825  delta = it->first;
826  stats.histo.resize(10);
827  } else
828  {
829  /* If not enough txs, don't reserve the last slot;
830  * spread evenly across all 10 bins.
831  */
832  stats.histo_98pc = 0;
833  it = agebytes.end();
834  factor = stats.txs_total > 9 ? 10 : stats.txs_total;
835  delta = now - stats.oldest;
836  stats.histo.resize(factor);
837  }
838  if (!delta)
839  delta = 1;
840  for (i2 = agebytes.begin(); i2 != it; i2++)
841  {
842  size_t i = (i2->first * factor - 1) / delta;
843  stats.histo[i].txs += i2->second.txs;
844  stats.histo[i].bytes += i2->second.bytes;
845  }
846  for (; i2 != agebytes.end(); i2++)
847  {
848  stats.histo[factor].txs += i2->second.txs;
849  stats.histo[factor].bytes += i2->second.bytes;
850  }
851  }
852  }
else if(0==res)
type_vec_type median(std::vector< type_vec_type > &v)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transactions()

void cryptonote::tx_memory_pool::get_transactions ( std::vector< transaction > &  txs,
bool  include_unrelayed_txes = true 
) const

get a list of all transactions in the pool

Parameters
txsreturn-by-reference the list of transactions
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 733 of file tx_pool.cpp.

734  {
735  CRITICAL_REGION_LOCAL(m_transactions_lock);
736  CRITICAL_REGION_LOCAL1(m_blockchain);
737  txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
738  m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
739  transaction tx;
740  if (!parse_and_validate_tx_from_blob(*bd, tx))
741  {
742  MERROR("Failed to parse tx from txpool");
743  // continue
744  return true;
745  }
746  tx.set_hash(txid);
747  txs.push_back(std::move(tx));
748  return true;
749  }, true, include_unrelayed_txes);
750  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transactions_and_spent_keys_info()

bool cryptonote::tx_memory_pool::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

get information about all transactions and key images in the pool

see documentation on tx_info and spent_key_image_info for more details

Parameters
tx_infosreturn-by-reference the transactions' information
key_image_infosreturn-by-reference the spent key images' information
include_sensitive_datainclude unrelayed txes and fields that are sensitive to the node privacy
Returns
true

Definition at line 855 of file tx_pool.cpp.

856  {
857  CRITICAL_REGION_LOCAL(m_transactions_lock);
858  CRITICAL_REGION_LOCAL1(m_blockchain);
859  tx_infos.reserve(m_blockchain.get_txpool_tx_count());
860  key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
861  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){
862  tx_info txi;
863  txi.id_hash = epee::string_tools::pod_to_hex(txid);
864  txi.tx_blob = *bd;
865  transaction tx;
866  if (!parse_and_validate_tx_from_blob(*bd, tx))
867  {
868  MERROR("Failed to parse tx from txpool");
869  // continue
870  return true;
871  }
872  tx.set_hash(txid);
873  txi.tx_json = obj_to_json_str(tx);
874  txi.blob_size = bd->size();
875  txi.weight = meta.weight;
876  txi.fee = meta.fee;
877  txi.kept_by_block = meta.kept_by_block;
878  txi.max_used_block_height = meta.max_used_block_height;
879  txi.max_used_block_id_hash = epee::string_tools::pod_to_hex(meta.max_used_block_id);
880  txi.last_failed_height = meta.last_failed_height;
881  txi.last_failed_id_hash = epee::string_tools::pod_to_hex(meta.last_failed_id);
882  // In restricted mode we do not include this data:
883  txi.receive_time = include_sensitive_data ? meta.receive_time : 0;
884  txi.relayed = meta.relayed;
885  // In restricted mode we do not include this data:
886  txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
887  txi.do_not_relay = meta.do_not_relay;
888  txi.double_spend_seen = meta.double_spend_seen;
889  txi.nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
890 
891  tx_infos.push_back(std::move(txi));
892  return true;
893  }, true, include_sensitive_data);
894 
895  txpool_tx_meta_t meta;
896  for (const key_images_container::value_type& kee : m_spent_key_images) {
897  const crypto::key_image& k_image = kee.first;
898  const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
899  spent_key_image_info ki;
900  ki.id_hash = epee::string_tools::pod_to_hex(k_image);
901  for (const crypto::hash& tx_id_hash : kei_image_set)
902  {
903  if (!include_sensitive_data)
904  {
905  try
906  {
907  if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
908  {
909  MERROR("Failed to get tx meta from txpool");
910  return false;
911  }
912  if (!meta.relayed)
913  // Do not include that transaction if in restricted mode and it's not relayed
914  continue;
915  }
916  catch (const std::exception &e)
917  {
918  MERROR("Failed to get tx meta from txpool: " << e.what());
919  return false;
920  }
921  }
922  ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
923  }
924  // Only return key images for which we have at least one tx that we can show for them
925  if (!ki.txs_hashes.empty())
926  key_image_infos.push_back(ki);
927  }
928  return true;
929  }
std::string obj_to_json_str(T &obj)
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transactions_count()

size_t cryptonote::tx_memory_pool::get_transactions_count ( bool  include_unrelayed_txes = true) const

get the total number of transactions in the pool

Returns
the number of transactions in the pool

Definition at line 726 of file tx_pool.cpp.

727  {
728  CRITICAL_REGION_LOCAL(m_transactions_lock);
729  CRITICAL_REGION_LOCAL1(m_blockchain);
730  return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
731  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_txpool_weight()

size_t cryptonote::tx_memory_pool::get_txpool_weight ( ) const

get the cumulative txpool weight in bytes

Returns
the cumulative txpool weight in bytes

Definition at line 364 of file tx_pool.cpp.

365  {
366  CRITICAL_REGION_LOCAL(m_transactions_lock);
367  return m_txpool_weight;
368  }

◆ have_tx()

bool cryptonote::tx_memory_pool::have_tx ( const crypto::hash id) const

checks if the pool has a transaction with the given hash

Parameters
idthe hash to look for
Returns
true if the transaction is in the pool, otherwise false

Definition at line 1025 of file tx_pool.cpp.

1026  {
1027  CRITICAL_REGION_LOCAL(m_transactions_lock);
1028  CRITICAL_REGION_LOCAL1(m_blockchain);
1029  return m_blockchain.get_db().txpool_has_tx(id);
1030  }
virtual bool txpool_has_tx(const crypto::hash &txid) const =0
check whether a txid is in the txpool
const BlockchainDB & get_db() const
get a reference to the BlockchainDB in use by Blockchain
Definition: blockchain.h:953
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

bool cryptonote::tx_memory_pool::init ( size_t  max_txpool_weight = 0)

loads pool state (if any) from disk, and initializes pool

Parameters
max_txpool_weightthe max weight in bytes
Returns
true

Definition at line 1554 of file tx_pool.cpp.

1555  {
1556  CRITICAL_REGION_LOCAL(m_transactions_lock);
1557  CRITICAL_REGION_LOCAL1(m_blockchain);
1558 
1559  m_txpool_max_weight = max_txpool_weight ? max_txpool_weight : DEFAULT_TXPOOL_MAX_WEIGHT;
1560  m_txs_by_fee_and_receive_time.clear();
1561  m_spent_key_images.clear();
1562  m_spent_utxos.clear();
1563  m_txpool_weight = 0;
1564  std::vector<crypto::hash> remove;
1565 
1566  // first add the not kept by block, then the kept by block,
1567  // to avoid rejection due to key image collision
1568  for (int pass = 0; pass < 2; ++pass)
1569  {
1570  const bool kept = pass == 1;
1571  bool r = m_blockchain.for_all_txpool_txes([this, &remove, kept](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) {
1572  if (!!kept != !!meta.kept_by_block)
1573  return true;
1576  {
1577  MWARNING("Failed to parse tx from txpool, removing");
1578  remove.push_back(txid);
1579  return true;
1580  }
1581  if (tx.version <= 2 && !insert_key_images(tx, txid, meta.kept_by_block))
1582  {
1583  MFATAL("Failed to insert key images from txpool tx");
1584  return false;
1585  }
1586  if (tx.version >= 3 && !insert_utxos(tx, txid, meta.kept_by_block))
1587  {
1588  MFATAL("Failed to insert utxos from txpool tx");
1589  return false;
1590  }
1591  m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.weight, meta.receive_time), txid);
1592  m_txpool_weight += meta.weight;
1593  return true;
1594  }, true);
1595  if (!r)
1596  return false;
1597  }
1598  if (!remove.empty())
1599  {
1600  LockedTXN lock(m_blockchain);
1601  for (const auto &txid: remove)
1602  {
1603  try
1604  {
1605  m_blockchain.remove_txpool_tx(txid);
1606  }
1607  catch (const std::exception &e)
1608  {
1609  MWARNING("Failed to remove corrupt transaction: " << txid);
1610  // ignore error
1611  }
1612  }
1613  lock.commit();
1614  }
1615 
1616  m_cookie = 0;
1617 
1618  // Ignore deserialization error
1619  return true;
1620  }
#define MFATAL(x)
Definition: misc_log_ex.h:72
#define MWARNING(x)
Definition: misc_log_ex.h:74
bool parse_and_validate_tx_prefix_from_blob(const blobdata &tx_blob, transaction_prefix &tx)
Here is the call graph for this function:

◆ lock()

void cryptonote::tx_memory_pool::lock ( void  ) const

locks the transaction pool

Definition at line 1078 of file tx_pool.cpp.

1079  {
1080  m_transactions_lock.lock();
1081  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_blockchain_dec()

bool cryptonote::tx_memory_pool::on_blockchain_dec ( uint64_t  new_block_height,
const crypto::hash top_block_id 
)

action to take when notified of a block removed from the blockchain

Currently does nothing

Parameters
new_block_heightthe height of the blockchain after the change
top_block_idthe hash of the new top block
Returns
true

Definition at line 1017 of file tx_pool.cpp.

1018  {
1019  CRITICAL_REGION_LOCAL(m_transactions_lock);
1020  m_input_cache.clear();
1021  m_parsed_tx_cache.clear();
1022  return true;
1023  }

◆ on_blockchain_inc()

bool cryptonote::tx_memory_pool::on_blockchain_inc ( uint64_t  new_block_height,
const crypto::hash top_block_id 
)

action to take when notified of a block added to the blockchain

Currently does nothing

Parameters
new_block_heightthe height of the blockchain after the change
top_block_idthe hash of the new top block
Returns
true

Definition at line 1009 of file tx_pool.cpp.

1010  {
1011  CRITICAL_REGION_LOCAL(m_transactions_lock);
1012  m_input_cache.clear();
1013  m_parsed_tx_cache.clear();
1014  return true;
1015  }

◆ on_idle()

void cryptonote::tx_memory_pool::on_idle ( )

action to take periodically

Currently checks transaction pool for stale ("stuck") transactions

Definition at line 587 of file tx_pool.cpp.

588  {
589  m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
590  }
bool do_call(functor_t functr)
Definition: math_helper.h:263
Here is the call graph for this function:
Here is the caller graph for this function:

◆ print_pool()

std::string cryptonote::tx_memory_pool::print_pool ( bool  short_format) const

get a string containing human-readable pool information

Parameters
short_formatwhether to use a shortened format for the info
Returns
the string

Definition at line 1325 of file tx_pool.cpp.

1326  {
1327  std::stringstream ss;
1328  CRITICAL_REGION_LOCAL(m_transactions_lock);
1329  CRITICAL_REGION_LOCAL1(m_blockchain);
1330  m_blockchain.for_all_txpool_txes([&ss, short_format](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *txblob) {
1331  ss << "id: " << txid << std::endl;
1332  if (!short_format) {
1334  if (!parse_and_validate_tx_from_blob(*txblob, tx))
1335  {
1336  MERROR("Failed to parse tx from txpool");
1337  return true; // continue
1338  }
1339  ss << obj_to_json_str(tx) << std::endl;
1340  }
1341  ss << "blob_size: " << (short_format ? "-" : std::to_string(txblob->size())) << std::endl
1342  << "weight: " << meta.weight << std::endl
1343  << "fee: " << print_etn(meta.fee) << std::endl
1344  << "kept_by_block: " << (meta.kept_by_block ? 'T' : 'F') << std::endl
1345  << "double_spend_seen: " << (meta.double_spend_seen ? 'T' : 'F') << std::endl
1346  << "nonexistent_utxo_seen: " << (meta.utxo_nonexistent_seen ? 'T' : 'F') << std::endl
1347  << "max_used_block_height: " << meta.max_used_block_height << std::endl
1348  << "max_used_block_id: " << meta.max_used_block_id << std::endl
1349  << "last_failed_height: " << meta.last_failed_height << std::endl
1350  << "last_failed_id: " << meta.last_failed_id << std::endl;
1351  return true;
1352  }, !short_format);
1353 
1354  return ss.str();
1355  }
std::string to_string(t_connection_type type)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_relayed()

void cryptonote::tx_memory_pool::set_relayed ( const std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &  txs)

tell the pool that certain transactions were just relayed

Parameters
txsthe list of transactions (and their hashes)

Definition at line 699 of file tx_pool.cpp.

700  {
701  CRITICAL_REGION_LOCAL(m_transactions_lock);
702  CRITICAL_REGION_LOCAL1(m_blockchain);
703  const time_t now = time(NULL);
704  LockedTXN lock(m_blockchain);
705  for (auto it = txs.begin(); it != txs.end(); ++it)
706  {
707  try
708  {
709  txpool_tx_meta_t meta;
710  if (m_blockchain.get_txpool_tx_meta(it->first, meta))
711  {
712  meta.relayed = true;
713  meta.last_relayed_time = now;
714  m_blockchain.update_txpool_tx(it->first, meta);
715  }
716  }
717  catch (const std::exception &e)
718  {
719  MERROR("Failed to update txpool transaction metadata: " << e.what());
720  // continue
721  }
722  }
723  lock.commit();
724  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_txpool_max_weight()

void cryptonote::tx_memory_pool::set_txpool_max_weight ( size_t  bytes)

set the max cumulative txpool weight in bytes

Parameters
bytesthe max cumulative txpool weight in bytes

Definition at line 370 of file tx_pool.cpp.

371  {
372  CRITICAL_REGION_LOCAL(m_transactions_lock);
373  m_txpool_max_weight = bytes;
374  }

◆ take_tx()

bool cryptonote::tx_memory_pool::take_tx ( const crypto::hash id,
transaction tx,
cryptonote::blobdata txblob,
size_t &  tx_weight,
uint64_t fee,
bool relayed,
bool do_not_relay,
bool double_spend_seen,
bool nonexistent_utxo_seen 
)

takes a transaction with the given hash from the pool

Parameters
idthe hash of the transaction
txreturn-by-reference the transaction taken
txblobreturn-by-reference the transaction as a blob
tx_weightreturn-by-reference the transaction's weight
feethe transaction fee
relayedreturn-by-reference was transaction relayed to us by the network?
do_not_relayreturn-by-reference is transaction not to be relayed to the network?
double_spend_seenreturn-by-reference was a double spend seen for that transaction?
nonexistent_utxo_seenreturn-by-reference was a nonexistent utxo seen for that transaction?
Returns
true unless the transaction cannot be found in the pool

Definition at line 531 of file tx_pool.cpp.

532  {
533  CRITICAL_REGION_LOCAL(m_transactions_lock);
534  CRITICAL_REGION_LOCAL1(m_blockchain);
535 
536  auto sorted_it = find_tx_in_sorted_container(id);
537 
538  try
539  {
540  LockedTXN lock(m_blockchain);
541  txpool_tx_meta_t meta;
542  if (!m_blockchain.get_txpool_tx_meta(id, meta))
543  {
544  MERROR("Failed to find tx in txpool");
545  return false;
546  }
547  txblob = m_blockchain.get_txpool_tx_blob(id);
548  auto ci = m_parsed_tx_cache.find(id);
549  if (ci != m_parsed_tx_cache.end())
550  {
551  tx = ci->second;
552  }
553  else if (!parse_and_validate_tx_from_blob(txblob, tx))
554  {
555  MERROR("Failed to parse tx from txpool");
556  return false;
557  }
558  else
559  {
560  tx.set_hash(id);
561  }
562  tx_weight = meta.weight;
563  fee = meta.fee;
564  relayed = meta.relayed;
565  do_not_relay = meta.do_not_relay;
566  double_spend_seen = meta.double_spend_seen;
567  nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
568 
569  // remove first, in case this throws, so key images aren't removed
570  m_blockchain.remove_txpool_tx(id);
571  m_txpool_weight -= tx_weight;
572  remove_transaction_keyimages(tx, id);
573  lock.commit();
574  }
575  catch (const std::exception &e)
576  {
577  MERROR("Failed to remove tx from txpool: " << e.what());
578  return false;
579  }
580 
581  if (sorted_it != m_txs_by_fee_and_receive_time.end())
582  m_txs_by_fee_and_receive_time.erase(sorted_it);
583  ++m_cookie;
584  return true;
585  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlock()

void cryptonote::tx_memory_pool::unlock ( void  ) const

unlocks the transaction pool

Definition at line 1083 of file tx_pool.cpp.

1084  {
1085  m_transactions_lock.unlock();
1086  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate()

size_t cryptonote::tx_memory_pool::validate ( uint8_t  version)

remove transactions from the pool which are no longer valid

With new versions of the currency, what conditions render a transaction invalid may change. This function clears those which were received before a version change and no longer conform to requirements.

Parameters
versionthe version the transactions must conform to
Returns
the number of transactions removed

Definition at line 1490 of file tx_pool.cpp.

1491  {
1492  CRITICAL_REGION_LOCAL(m_transactions_lock);
1493  CRITICAL_REGION_LOCAL1(m_blockchain);
1494  size_t tx_weight_limit = get_transaction_weight_limit(version);
1495  std::unordered_set<crypto::hash> remove;
1496 
1497  m_txpool_weight = 0;
1498  m_blockchain.for_all_txpool_txes([this, &remove, tx_weight_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
1499  m_txpool_weight += meta.weight;
1500  if (meta.weight > tx_weight_limit) {
1501  LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.weight << " bytes), removing it from pool");
1502  remove.insert(txid);
1503  }
1504  else if (m_blockchain.have_tx(txid)) {
1505  LOG_PRINT_L1("Transaction " << txid << " is in the blockchain, removing it from pool");
1506  remove.insert(txid);
1507  }
1508  return true;
1509  }, false);
1510 
1511  size_t n_removed = 0;
1512  if (!remove.empty())
1513  {
1514  LockedTXN lock(m_blockchain);
1515  for (const crypto::hash &txid: remove)
1516  {
1517  try
1518  {
1519  cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
1521  if (!parse_and_validate_tx_from_blob(txblob, tx))
1522  {
1523  MERROR("Failed to parse tx from txpool");
1524  continue;
1525  }
1526  // remove tx from db first
1527  m_blockchain.remove_txpool_tx(txid);
1528  m_txpool_weight -= get_transaction_weight(tx, txblob.size());
1529  remove_transaction_keyimages(tx, txid);
1530  auto sorted_it = find_tx_in_sorted_container(txid);
1531  if (sorted_it == m_txs_by_fee_and_receive_time.end())
1532  {
1533  LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
1534  }
1535  else
1536  {
1537  m_txs_by_fee_and_receive_time.erase(sorted_it);
1538  }
1539  ++n_removed;
1540  }
1541  catch (const std::exception &e)
1542  {
1543  MERROR("Failed to remove invalid tx from pool");
1544  // continue
1545  }
1546  }
1547  lock.commit();
1548  }
1549  if (n_removed > 0)
1550  ++m_cookie;
1551  return n_removed;
1552  }
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
Definition: blockchain.cpp:164
Here is the call graph for this function:

The documentation for this class was generated from the following files: