Electroneum
tx_pool.cpp
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 // Copyrights(c) 2014-2019, The Monero Project
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31 
32 #include <algorithm>
33 #include <boost/filesystem.hpp>
34 #include <unordered_set>
35 #include <vector>
36 
37 #include "tx_pool.h"
38 #include "cryptonote_tx_utils.h"
40 #include "cryptonote_config.h"
41 #include "blockchain.h"
44 #include "int-util.h"
45 #include "misc_language.h"
46 #include "warnings.h"
47 #include "common/perf_timer.h"
48 #include "crypto/hash.h"
49 #include "string_tools.h"
50 
51 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
52 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "txpool"
53 
54 DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
55 
56 using namespace crypto;
57 
58 namespace cryptonote
59 {
60  namespace
61  {
62  //TODO: constants such as these should at least be in the header,
63  // but probably somewhere more accessible to the rest of the
64  // codebase. As it stands, it is at best nontrivial to test
65  // whether or not changing these parameters (or adding new)
66  // will work correctly.
67  time_t const MIN_RELAY_TIME = (60 * 5); // only start re-relaying transactions after that many seconds
68  time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
69  float const ACCEPT_THRESHOLD = 1.0f;
70 
71  // a kind of increasing backoff within min/max bounds
72  uint64_t get_relay_delay(time_t now, time_t received)
73  {
74  time_t d = (now - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME;
75  if (d > MAX_RELAY_TIME)
76  d = MAX_RELAY_TIME;
77  return d;
78  }
79 
80  uint64_t template_accept_threshold(uint64_t amount)
81  {
82  return amount * ACCEPT_THRESHOLD;
83  }
84 
85  uint64_t get_transaction_weight_limit(uint8_t version)
86  {
87  // from v8, limit a tx to 50% of the minimum block weight
88  if (version >= 8)
90  else
92  }
93 
94  // This class is meant to create a batch when none currently exists.
95  // If a batch exists, it can't be from another thread, since we can
96  // only be called with the txpool lock taken, and it is held during
97  // the whole prepare/handle/cleanup incoming block sequence.
98  class LockedTXN {
99  public:
100  LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false), m_active(false) {
101  m_batch = m_blockchain.get_db().batch_start();
102  m_active = true;
103  }
104  void commit() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_stop(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::commit filtering exception: " << e.what()); } }
105  void abort() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_abort(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::abort filtering exception: " << e.what()); } }
106  ~LockedTXN() { abort(); }
107  private:
108  Blockchain &m_blockchain;
109  bool m_batch;
110  bool m_active;
111  };
112  }
113  //---------------------------------------------------------------------------------
114  //---------------------------------------------------------------------------------
115  tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_cookie(0)
116  {
117 
118  }
119  //---------------------------------------------------------------------------------
120  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)
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  }
352  //---------------------------------------------------------------------------------
353  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)
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  }
363  //---------------------------------------------------------------------------------
365  {
366  CRITICAL_REGION_LOCAL(m_transactions_lock);
367  return m_txpool_weight;
368  }
369  //---------------------------------------------------------------------------------
371  {
372  CRITICAL_REGION_LOCAL(m_transactions_lock);
373  m_txpool_max_weight = bytes;
374  }
375  //---------------------------------------------------------------------------------
376  void tx_memory_pool::prune(size_t bytes)
377  {
378  CRITICAL_REGION_LOCAL(m_transactions_lock);
379  if (bytes == 0)
380  bytes = m_txpool_max_weight;
381  CRITICAL_REGION_LOCAL1(m_blockchain);
382  LockedTXN lock(m_blockchain);
383  bool changed = false;
384 
385  // this will never remove the first one, but we don't care
386  auto it = --m_txs_by_fee_and_receive_time.end();
387  while (it != m_txs_by_fee_and_receive_time.begin())
388  {
389  if (m_txpool_weight <= bytes)
390  break;
391  try
392  {
393  const crypto::hash &txid = it->second;
394  txpool_tx_meta_t meta;
395  if (!m_blockchain.get_txpool_tx_meta(txid, meta))
396  {
397  MERROR("Failed to find tx in txpool");
398  return;
399  }
400  // don't prune the kept_by_block ones, they're likely added because we're adding a block with those
401  if (meta.kept_by_block)
402  {
403  --it;
404  continue;
405  }
406  cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
409  {
410  MERROR("Failed to parse tx from txpool");
411  return;
412  }
413  // remove first, in case this throws, so key images aren't removed
414  MINFO("Pruning tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first);
415  m_blockchain.remove_txpool_tx(txid);
416  m_txpool_weight -= meta.weight;
417  remove_transaction_keyimages(tx, txid);
418  MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first);
419  m_txs_by_fee_and_receive_time.erase(it--);
420  changed = true;
421  }
422  catch (const std::exception &e)
423  {
424  MERROR("Error while pruning txpool: " << e.what());
425  return;
426  }
427  }
428  lock.commit();
429  if (changed)
430  ++m_cookie;
431  if (m_txpool_weight > bytes)
432  MINFO("Pool weight after pruning is larger than limit: " << m_txpool_weight << "/" << bytes);
433  }
434  //---------------------------------------------------------------------------------
435  bool tx_memory_pool::insert_key_images(const transaction_prefix &tx, const crypto::hash &id, bool kept_by_block)
436  {
437  for(const auto& in: tx.vin)
438  {
439  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
440  std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
441  CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block
442  << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
443  << "tx_id=" << id );
444  auto ins_res = kei_image_set.insert(id);
445  CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
446  }
447  ++m_cookie;
448  return true;
449  }
450  //---------------------------------------------------------------------------------
451  bool tx_memory_pool::insert_utxos(const transaction_prefix &tx, const crypto::hash &id, bool kept_by_block)
452  {
453  for(const auto& in: tx.vin)
454  {
455  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, txin, false);
457  std::unordered_set<crypto::hash>& utxo_set = m_spent_utxos[txin_key];
458  CHECK_AND_ASSERT_MES(kept_by_block || utxo_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block
459  << ", utxo_set.size()=" << utxo_set.size() << ENDL << "txin=" << txin_key << ENDL
460  << "tx_id=" << id );
461  auto ins_res = utxo_set.insert(id);
462  CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in utxo set");
463  }
464  ++m_cookie;
465  return true;
466  }
467  //---------------------------------------------------------------------------------
468  //FIXME: Can return early before removal of all of the key images.
469  // At the least, need to make sure that a false return here
470  // is treated properly. Should probably not return early, however.
471  bool tx_memory_pool::remove_transaction_keyimages(const transaction_prefix& tx, const crypto::hash &actual_hash)
472  {
473  CRITICAL_REGION_LOCAL(m_transactions_lock);
474  CRITICAL_REGION_LOCAL1(m_blockchain);
475  // ND: Speedup
476  for(const txin_v& vi: tx.vin)
477  {
478  if(vi.type() == typeid(txin_to_key))
479  {
480  const auto &txin = boost::get<txin_to_key>(vi);
481 
482  auto it = m_spent_key_images.find(txin.k_image);
483  CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << txin.k_image << ENDL
484  << "transaction id = " << actual_hash);
485  std::unordered_set<crypto::hash>& key_image_set = it->second;
486  CHECK_AND_ASSERT_MES(key_image_set.size(), false, "empty key_image set, img=" << txin.k_image << ENDL
487  << "transaction id = " << actual_hash);
488 
489  auto it_in_set = key_image_set.find(actual_hash);
490  CHECK_AND_ASSERT_MES(it_in_set != key_image_set.end(), false, "transaction id not found in key_image set, img=" << txin.k_image << ENDL
491  << "transaction id = " << actual_hash);
492  key_image_set.erase(it_in_set);
493  if(!key_image_set.size())
494  {
495  //it is now empty hash container for this key_image
496  m_spent_key_images.erase(it);
497  }
498  }
499  else if (vi.type() == typeid(txin_to_key_public))
500  {
501  const auto &txin = boost::get<txin_to_key_public>(vi);
502 
504 
505  auto it = m_spent_utxos.find(txin_key);
506  CHECK_AND_ASSERT_MES(it != m_spent_utxos.end(), false, "failed to find transaction input in utxos. utxo=" << txin_key << ENDL
507  << "transaction id = " << actual_hash);
508  std::unordered_set<crypto::hash>& utxo_set = it->second;
509  CHECK_AND_ASSERT_MES(utxo_set.size(), false, "empty utxo set, utxo=" << txin_key << ENDL
510  << "transaction id = " << actual_hash);
511 
512  auto it_in_set = utxo_set.find(actual_hash);
513  CHECK_AND_ASSERT_MES(it_in_set != utxo_set.end(), false, "transaction id not found in utxo set, utxo=" << txin_key << ENDL
514  << "transaction id = " << actual_hash);
515  utxo_set.erase(it_in_set);
516  if(!utxo_set.size())
517  {
518  //it is now empty hash container for this key_image
519  m_spent_utxos.erase(it);
520  }
521  }
522  else
523  {
524  return false;
525  }
526  }
527  ++m_cookie;
528  return true;
529  }
530  //---------------------------------------------------------------------------------
531  bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen, bool &nonexistent_utxo_seen)
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  }
586  //---------------------------------------------------------------------------------
588  {
589  m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
590  }
591  //---------------------------------------------------------------------------------
592  sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(const crypto::hash& id) const
593  {
594  return std::find_if( m_txs_by_fee_and_receive_time.begin(), m_txs_by_fee_and_receive_time.end()
595  , [&](const sorted_tx_container::value_type& a){
596  return a.second == id;
597  }
598  );
599  }
600  //---------------------------------------------------------------------------------
601  //TODO: investigate whether boolean return is appropriate
602  bool tx_memory_pool::remove_stuck_transactions()
603  {
604  CRITICAL_REGION_LOCAL(m_transactions_lock);
605  CRITICAL_REGION_LOCAL1(m_blockchain);
606  std::list<std::pair<crypto::hash, uint64_t>> remove;
607  m_blockchain.for_all_txpool_txes([this, &remove](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
608  uint64_t tx_age = time(nullptr) - meta.receive_time;
609  uint32_t mempool_lifetime = m_blockchain.get_mempool_tx_livetime();
610  if((tx_age > mempool_lifetime && !meta.kept_by_block) ||
611  (tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && meta.kept_by_block) )
612  {
613  LOG_PRINT_L1("Tx " << txid << " removed from tx pool due to outdated, age: " << tx_age );
614  auto sorted_it = find_tx_in_sorted_container(txid);
615  if (sorted_it == m_txs_by_fee_and_receive_time.end())
616  {
617  LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
618  }
619  else
620  {
621  m_txs_by_fee_and_receive_time.erase(sorted_it);
622  }
623  m_timed_out_transactions.insert(txid);
624  remove.push_back(std::make_pair(txid, meta.weight));
625  }
626  return true;
627  }, false);
628 
629  if (!remove.empty())
630  {
631  LockedTXN lock(m_blockchain);
632  for (const std::pair<crypto::hash, uint64_t> &entry: remove)
633  {
634  const crypto::hash &txid = entry.first;
635  try
636  {
637  cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
640  {
641  MERROR("Failed to parse tx from txpool");
642  // continue
643  }
644  else
645  {
646  // remove first, so we only remove key images if the tx removal succeeds
647  m_blockchain.remove_txpool_tx(txid);
648  m_txpool_weight -= entry.second;
649  remove_transaction_keyimages(tx, txid);
650  }
651  }
652  catch (const std::exception &e)
653  {
654  MWARNING("Failed to remove stuck transaction: " << txid);
655  // ignore error
656  }
657  }
658  lock.commit();
659  ++m_cookie;
660  }
661  return true;
662  }
663  //---------------------------------------------------------------------------------
664  //TODO: investigate whether boolean return is appropriate
665  bool tx_memory_pool::get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs) const
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  }
698  //---------------------------------------------------------------------------------
699  void tx_memory_pool::set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs)
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  }
725  //---------------------------------------------------------------------------------
726  size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
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  }
732  //---------------------------------------------------------------------------------
733  void tx_memory_pool::get_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes) const
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  }
751  //------------------------------------------------------------------
752  void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes) const
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  }
762  //------------------------------------------------------------------
763  void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes) const
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  }
774  //------------------------------------------------------------------
775  void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes) const
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  }
853  //------------------------------------------------------------------
854  //TODO: investigate whether boolean return is appropriate
855  bool 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) const
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;
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;
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;
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;
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  }
930  //---------------------------------------------------------------------------------
931  bool 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
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;
955  txi.receive_time = meta.receive_time;
956  txi.relayed = meta.relayed;
958  txi.do_not_relay = meta.do_not_relay;
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  }
979  //---------------------------------------------------------------------------------
980  bool tx_memory_pool::check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool> spent) const
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  }
994  //---------------------------------------------------------------------------------
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  }
1008  //---------------------------------------------------------------------------------
1009  bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id)
1010  {
1011  CRITICAL_REGION_LOCAL(m_transactions_lock);
1012  m_input_cache.clear();
1013  m_parsed_tx_cache.clear();
1014  return true;
1015  }
1016  //---------------------------------------------------------------------------------
1017  bool tx_memory_pool::on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id)
1018  {
1019  CRITICAL_REGION_LOCAL(m_transactions_lock);
1020  m_input_cache.clear();
1021  m_parsed_tx_cache.clear();
1022  return true;
1023  }
1024  //---------------------------------------------------------------------------------
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  }
1031 
1032  //---------------------------------------------------------------------------------
1033  bool tx_memory_pool::key_images_already_spent(const transaction& tx) const
1034  {
1035  CRITICAL_REGION_LOCAL(m_transactions_lock);
1036  CRITICAL_REGION_LOCAL1(m_blockchain);
1037  for(const auto& in: tx.vin)
1038  {
1039  if(in.type() == typeid(txin_to_key))
1040  {
1041  const auto &tokey_in = boost::get<txin_to_key>(in);
1042  if(have_tx_keyimg_as_spent(tokey_in.k_image)) // key_image
1043  return true;
1044  }
1045  }
1046  return false;
1047  }
1048  //---------------------------------------------------------------------------------
1049  bool tx_memory_pool::utxo_nonexistent(const transaction& tx) const
1050  {
1051  CRITICAL_REGION_LOCAL(m_transactions_lock);
1052  CRITICAL_REGION_LOCAL1(m_blockchain);
1053  for(const auto& in: tx.vin)
1054  {
1055  if (in.type() == typeid(txin_to_key_public))
1056  {
1057  const auto &tokey_in = boost::get<txin_to_key_public>(in);
1058  if(have_tx_utxo_as_spent(tokey_in)) // UTXO
1059  return true;
1060  }
1061  }
1062  return false;
1063  }
1064  //---------------------------------------------------------------------------------
1065  bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const
1066  {
1067  CRITICAL_REGION_LOCAL(m_transactions_lock);
1068  return m_spent_key_images.end() != m_spent_key_images.find(key_im);
1069  }
1070  //---------------------------------------------------------------------------------
1071  bool tx_memory_pool::have_tx_utxo_as_spent(const txin_to_key_public& in) const
1072  {
1073  CRITICAL_REGION_LOCAL(m_transactions_lock);
1075  return m_spent_utxos.end() != m_spent_utxos.find(txin_key);
1076  }
1077  //---------------------------------------------------------------------------------
1079  {
1080  m_transactions_lock.lock();
1081  }
1082  //---------------------------------------------------------------------------------
1084  {
1085  m_transactions_lock.unlock();
1086  }
1087  //---------------------------------------------------------------------------------
1088  bool tx_memory_pool::check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block) const
1089  {
1090  if (!kept_by_block)
1091  {
1092  const std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>>::const_iterator i = m_input_cache.find(txid);
1093  if (i != m_input_cache.end())
1094  {
1095  max_used_block_height = std::get<2>(i->second);
1096  max_used_block_id = std::get<3>(i->second);
1097  tvc = std::get<1>(i->second);
1098  return std::get<0>(i->second);
1099  }
1100  }
1101  bool ret = m_blockchain.check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, kept_by_block);
1102  if (!kept_by_block)
1103  m_input_cache.insert(std::make_pair(txid, std::make_tuple(ret, tvc, max_used_block_height, max_used_block_id)));
1104  return ret;
1105  }
1106  //---------------------------------------------------------------------------------
1107  bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction &tx) const
1108  {
1109  struct transction_parser
1110  {
1111  transction_parser(const cryptonote::blobdata &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
1112  cryptonote::transaction &operator()()
1113  {
1114  if (!parsed)
1115  {
1116  if (!parse_and_validate_tx_from_blob(txblob, tx))
1117  throw std::runtime_error("failed to parse transaction blob");
1118  tx.set_hash(txid);
1119  parsed = true;
1120  }
1121  return tx;
1122  }
1123  const cryptonote::blobdata &txblob;
1124  const crypto::hash &txid;
1125  transaction &tx;
1126  bool parsed;
1127  } lazy_tx(txblob, txid, tx);
1128 
1129  //not the best implementation at this time, sorry :(
1130  //check is ring_signature already checked ?
1131  if(txd.max_used_block_id == null_hash)
1132  {//not checked, lets try to check
1133 
1134  if(txd.last_failed_id != null_hash && m_blockchain.get_current_blockchain_height() > txd.last_failed_height && txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
1135  return false;//we already sure that this tx is broken for this height
1136 
1137  tx_verification_context tvc;
1138  if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
1139  {
1140  txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
1141  txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
1142  return false;
1143  }
1144  }else
1145  {
1146  if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height())
1147  return false;
1148  if(true)
1149  {
1150  //if we already failed on this height and id, skip actual ring signature check
1151  if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
1152  return false;
1153  //check ring signature again, it is possible (with very small chance) that this transaction become again valid
1154  tx_verification_context tvc;
1155  if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
1156  {
1157  txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
1158  txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
1159  return false;
1160  }
1161  }
1162  }
1163 
1164  //if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure
1165  if(tx.version < 3 && m_blockchain.key_images_already_spent(lazy_tx()))
1166  {
1167  txd.double_spend_seen = true;
1168  return false;
1169  }
1170  if(tx.version > 2 && m_blockchain.utxo_nonexistent(lazy_tx()))
1171  {
1172  txd.utxo_nonexistent_seen = true;
1173  return false;
1174  }
1175 
1176  //transaction is ok.
1177  return true;
1178  }
1179  //---------------------------------------------------------------------------------
1180  bool tx_memory_pool::have_key_images(const std::unordered_set<crypto::key_image>& k_images, const transaction_prefix& tx)
1181  {
1182  for(size_t i = 0; i!= tx.vin.size(); i++)
1183  {
1184  if(tx.vin[i].type() == typeid(txin_to_key))
1185  {
1186  const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1187  if(k_images.count(itk.k_image))
1188  return true;
1189  }
1190  }
1191  return false;
1192  }
1193  //---------------------------------------------------------------------------------
1194  bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images, const transaction_prefix& tx)
1195  {
1196  for(size_t i = 0; i!= tx.vin.size(); i++)
1197  {
1198  if(tx.vin[i].type() == typeid(txin_to_key))
1199  {
1200  const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1201  auto i_res = k_images.insert(itk.k_image);
1202  CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image);
1203  }
1204  }
1205  return true;
1206  }
1207  //---------------------------------------------------------------------------------
1208  bool tx_memory_pool::have_utxos(const std::unordered_set<std::string>& utxos, const transaction_prefix& tx)
1209  {
1210  for(size_t i = 0; i!= tx.vin.size(); i++)
1211  {
1212  if(tx.vin[i].type() == typeid(txin_to_key_public))
1213  {
1214  const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1216  if(utxos.count(txin_key))
1217  return true;
1218  }
1219 
1220  }
1221  return false;
1222  }
1223  //---------------------------------------------------------------------------------
1224  bool tx_memory_pool::append_utxos(std::unordered_set<std::string>& utxos, const transaction_prefix& tx)
1225  {
1226  for(size_t i = 0; i!= tx.vin.size(); i++)
1227  {
1228  if(tx.vin[i].type() == typeid(txin_to_key_public))
1229  {
1230  const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1231 
1233  auto i_res = utxos.insert(txin_key);
1234  CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: utxo pool cache - inserted duplicate image in set: " << txin_key);
1235  }
1236  }
1237  return true;
1238  }
1239  //---------------------------------------------------------------------------------
1240  void tx_memory_pool::mark_double_spend_or_nonexistent_utxo(const transaction &tx)
1241  {
1242  CRITICAL_REGION_LOCAL(m_transactions_lock);
1243  CRITICAL_REGION_LOCAL1(m_blockchain);
1244  bool changed = false;
1245  LockedTXN lock(m_blockchain);
1246  for(size_t i = 0; i!= tx.vin.size(); i++)
1247  {
1248  if(tx.vin[i].type() == typeid(txin_to_key))
1249  {
1250  CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, void());
1251  const key_images_container::const_iterator it = m_spent_key_images.find(itk.k_image);
1252  if (it != m_spent_key_images.end())
1253  {
1254  for (const crypto::hash &txid: it->second)
1255  {
1256  txpool_tx_meta_t meta;
1257  if (!m_blockchain.get_txpool_tx_meta(txid, meta))
1258  {
1259  MERROR("Failed to find tx meta in txpool");
1260  // continue, not fatal
1261  continue;
1262  }
1263  if (!meta.double_spend_seen)
1264  {
1265  MDEBUG("Marking " << txid << " as double spending " << itk.k_image);
1266  meta.double_spend_seen = true;
1267  changed = true;
1268  try
1269  {
1270  m_blockchain.update_txpool_tx(txid, meta);
1271  }
1272  catch (const std::exception &e)
1273  {
1274  MERROR("Failed to update tx meta: " << e.what());
1275  // continue, not fatal
1276  }
1277  }
1278  }
1279  }
1280  }
1281  else if (tx.vin[i].type() == typeid(txin_to_key_public))
1282  {
1283  CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key_public, itk, void());
1285  const utxos_container::const_iterator it = m_spent_utxos.find(txin_key);
1286  if (it != m_spent_utxos.end())
1287  {
1288  for (const crypto::hash &txid: it->second)
1289  {
1290  txpool_tx_meta_t meta;
1291  if (!m_blockchain.get_txpool_tx_meta(txid, meta))
1292  {
1293  MERROR("Failed to find tx meta in txpool");
1294  // continue, not fatal
1295  continue;
1296  }
1297  if (!meta.double_spend_seen)
1298  {
1299  MDEBUG("Marking " << txid << " as double spending " << txin_key);
1300  meta.utxo_nonexistent_seen = true;
1301  changed = true;
1302  try
1303  {
1304  m_blockchain.update_txpool_tx(txid, meta);
1305  }
1306  catch (const std::exception &e)
1307  {
1308  MERROR("Failed to update tx meta: " << e.what());
1309  // continue, not fatal
1310  }
1311  }
1312  }
1313  }
1314  }
1315  else
1316  {
1317  return;
1318  }
1319  }
1320  lock.commit();
1321  if (changed)
1322  ++m_cookie;
1323  }
1324  //---------------------------------------------------------------------------------
1325  std::string tx_memory_pool::print_pool(bool short_format) const
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  }
1356  //---------------------------------------------------------------------------------
1357  //TODO: investigate whether boolean return is appropriate
1358  bool 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)
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  }
1489  //---------------------------------------------------------------------------------
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  }
1553  //---------------------------------------------------------------------------------
1554  bool tx_memory_pool::init(size_t max_txpool_weight)
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  }
1621 
1622  //---------------------------------------------------------------------------------
1624  {
1625  return true;
1626  }
1627 }
else if(0==res)
time_t time
Definition: blockchain.cpp:93
virtual bool txpool_has_tx(const crypto::hash &txid) const =0
check whether a txid is in the txpool
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block's hash given a height
Definition: blockchain.cpp:787
bool utxo_nonexistent(const transaction &tx) const
check if any utxo in a transaction has already been spent (v3 tx onwards)
bool check_fee(size_t tx_weight, uint64_t fee) const
validate a transaction's fee
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
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)
network_type get_nettype() const
get blockchain nettype
Definition: blockchain.h:1048
uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) const
bool key_images_already_spent(const transaction &tx) const
check if any key image in a transaction has already been spent
bool check_tx_outputs(const transaction &tx, tx_verification_context &tvc)
check that a transaction's outputs conform to current standards
bool check_tx_inputs(transaction &tx, uint64_t &pmax_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block=false)
validates a transaction's inputs
void remove_txpool_tx(const crypto::hash &txid)
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
uint32_t get_mempool_tx_livetime() const
const BlockchainDB & get_db() const
get a reference to the BlockchainDB in use by Blockchain
Definition: blockchain.h:953
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
Definition: blockchain.cpp:164
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
void set_hash(const crypto::hash &h)
void unlock() const
unlocks the transaction pool
Definition: tx_pool.cpp:1083
void lock() const
locks the transaction pool
Definition: tx_pool.cpp:1078
void on_idle()
action to take periodically
Definition: tx_pool.cpp:587
void set_relayed(const std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs)
tell the pool that certain transactions were just relayed
Definition: tx_pool.cpp:699
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
Definition: tx_pool.cpp:931
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
Definition: tx_pool.cpp:1017
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.
Definition: tx_pool.cpp:1358
bool have_tx(const crypto::hash &id) const
checks if the pool has a transaction with the given hash
Definition: tx_pool.cpp:1025
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
Definition: tx_pool.cpp:1009
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
Definition: tx_pool.cpp:752
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
void set_txpool_max_weight(size_t bytes)
set the max cumulative txpool weight in bytes
Definition: tx_pool.cpp:370
void get_transactions(std::vector< transaction > &txs, bool include_unrelayed_txes=true) const
get a list of all transactions in the pool
Definition: tx_pool.cpp:733
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
Definition: tx_pool.cpp:531
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
Definition: tx_pool.cpp:855
bool init(size_t max_txpool_weight=0)
loads pool state (if any) from disk, and initializes pool
Definition: tx_pool.cpp:1554
std::string print_pool(bool short_format) const
get a string containing human-readable pool information
Definition: tx_pool.cpp:1325
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
Definition: tx_pool.cpp:763
size_t validate(uint8_t version)
remove transactions from the pool which are no longer valid
Definition: tx_pool.cpp:1490
size_t get_txpool_weight() const
get the cumulative txpool weight in bytes
Definition: tx_pool.cpp:364
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
Definition: tx_pool.cpp:775
size_t get_transactions_count(bool include_unrelayed_txes=true) const
get the total number of transactions in the pool
Definition: tx_pool.cpp:726
bool get_relayable_transactions(std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs) const
get a list of all relayable transactions and their hashes
Definition: tx_pool.cpp:665
bool get_transaction(const crypto::hash &h, cryptonote::blobdata &txblob) const
get a specific transaction from the pool
Definition: tx_pool.cpp:995
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
Definition: tx_pool.cpp:980
bool deinit()
attempts to save the transaction pool state to disk
Definition: tx_pool.cpp:1623
bool do_call(functor_t functr)
Definition: math_helper.h:263
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE
#define DEFAULT_TXPOOL_MAX_WEIGHT
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME
#define HF_VERSION_PER_BYTE_FEE
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val)
#define MERROR(x)
Definition: misc_log_ex.h:73
#define MFATAL(x)
Definition: misc_log_ex.h:72
#define MWARNING(x)
Definition: misc_log_ex.h:74
#define MDEBUG(x)
Definition: misc_log_ex.h:76
#define ENDL
Definition: misc_log_ex.h:149
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
#define MINFO(x)
Definition: misc_log_ex.h:75
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
crypto namespace.
Definition: crypto.cpp:58
POD_CLASS key_image
Definition: crypto.h:102
POD_CLASS hash
Definition: hash.h:50
std::unordered_map< crypto::key_image, std::vector< crypto::hash > > key_images_with_tx_hashes
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
std::string obj_to_json_str(T &obj)
uint64_t get_outs_etn_amount(const transaction &tx)
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)
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
size_t get_min_block_weight(uint8_t version)
crypto::hash get_transaction_hash(const transaction &t)
bool check_outs_valid(const transaction &tx)
std::string blobdata
Definition: blobdatatype.h:39
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
bool parse_and_validate_tx_prefix_from_blob(const blobdata &tx_blob, transaction_prefix &tx)
bool check_inputs_types_supported(const transaction &tx)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
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)
type_vec_type median(std::vector< type_vec_type > &v)
std::string to_string(t_connection_type type)
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
std::string buff_to_hex_nodelimer(const std::string &src)
Definition: string_tools.h:87
version
Supported socks variants.
Definition: socks.h:58
key commit(etn_amount amount, const key &mask)
Definition: rctOps.cpp:336
tuple make_tuple()
Definition: gtest-tuple.h:675
::std::string string
Definition: gtest-port.h:1097
const T & move(const T &t)
Definition: gtest-port.h:1317
#define PERF_TIMER(name)
Definition: perf_timer.h:82
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
#define false
Definition: stdbool.h:38
unsigned int uint32_t
Definition: stdint.h:126
unsigned char uint8_t
Definition: stdint.h:124
unsigned __int64 uint64_t
Definition: stdint.h:136
std::vector< crypto::hash > tx_hashes
cryptonote::transaction tx
std::vector< txpool_histo > histo
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
DISABLE_VS_WARNINGS(4244 4345 4503) using namespace crypto