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 #include <regex>
37 #include <bitset>
38 
39 #include "tx_pool.h"
40 #include "cryptonote_tx_utils.h"
42 #include "cryptonote_config.h"
43 #include "blockchain.h"
46 #include "int-util.h"
47 #include "misc_language.h"
48 #include "warnings.h"
49 #include "common/perf_timer.h"
50 #include "crypto/hash.h"
51 #include "string_tools.h"
52 
53 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
54 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "txpool"
55 
56 DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
57 
58 using namespace crypto;
59 
60 namespace cryptonote
61 {
62  namespace
63  {
64  //TODO: constants such as these should at least be in the header,
65  // but probably somewhere more accessible to the rest of the
66  // codebase. As it stands, it is at best nontrivial to test
67  // whether or not changing these parameters (or adding new)
68  // will work correctly.
69  time_t const MIN_RELAY_TIME = (60 * 5); // only start re-relaying transactions after that many seconds
70  time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
71  float const ACCEPT_THRESHOLD = 1.0f;
72 
73  // a kind of increasing backoff within min/max bounds
74  uint64_t get_relay_delay(time_t now, time_t received)
75  {
76  time_t d = (now - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME;
77  if (d > MAX_RELAY_TIME)
78  d = MAX_RELAY_TIME;
79  return d;
80  }
81 
82  uint64_t template_accept_threshold(uint64_t amount)
83  {
84  return amount * ACCEPT_THRESHOLD;
85  }
86 
87  uint64_t get_transaction_weight_limit(uint8_t version)
88  {
89  // from v8, limit a tx to 50% of the minimum block weight
90  if (version >= 8)
92  else
94  }
95 
96  // This class is meant to create a batch when none currently exists.
97  // If a batch exists, it can't be from another thread, since we can
98  // only be called with the txpool lock taken, and it is held during
99  // the whole prepare/handle/cleanup incoming block sequence.
100  class LockedTXN {
101  public:
102  LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false), m_active(false) {
103  m_batch = m_blockchain.get_db().batch_start();
104  m_active = true;
105  }
106  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()); } }
107  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()); } }
108  ~LockedTXN() { abort(); }
109  private:
110  Blockchain &m_blockchain;
111  bool m_batch;
112  bool m_active;
113  };
114  }
115  //---------------------------------------------------------------------------------
116  //---------------------------------------------------------------------------------
117  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)
118  {
119 
120  }
121  //---------------------------------------------------------------------------------
122  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)
123  {
124  // this should already be called with that lock, but let's make it explicit for clarity
125  CRITICAL_REGION_LOCAL(m_transactions_lock);
126 
128  if (tx.version == 0)
129  {
130  // v0 never accepted
131  LOG_PRINT_L1("transaction version 0 is invalid");
132  tvc.m_verification_failed = true;
133  return false;
134  }
135 
136  // we do not accept transactions that timed out before, unless they're
137  // kept_by_block
138  if (!kept_by_block && m_timed_out_transactions.find(id) != m_timed_out_transactions.end())
139  {
140  // not clear if we should set that, since verifivation (sic) did not fail before, since
141  // the tx was accepted before timing out.
142  tvc.m_verification_failed = true;
143  return false;
144  }
145 
147  {
148  tvc.m_verification_failed = true;
149  tvc.m_invalid_input = true;
150  return false;
151  }
152 
153  if(!check_outs_valid(tx))
154  {
155  tvc.m_verification_failed = true;
156  tvc.m_invalid_output = true;
157  return false;
158  }
159 
160  // fee per kilobyte, size rounded up.
161  uint64_t fee = 0;
162 
163  uint64_t inputs_amount = 0;
164  if(!get_inputs_etn_amount(tx, inputs_amount))
165  {
166  tvc.m_verification_failed = true;
167  return false;
168  }
169 
170  uint64_t outputs_amount = get_outs_etn_amount(tx);
171  fee = inputs_amount - outputs_amount;
172 
173  if(tx.version == 3 && m_blockchain.get_current_blockchain_height() > (m_blockchain.get_nettype() == MAINNET ? 1811310 : 1455270)) {
174  if(outputs_amount != inputs_amount)
175  {
176  LOG_PRINT_L1("transaction fee isnt zero: outputs_amount != inputs_amount, rejecting.");
177  tvc.m_verification_failed = true;
178  return false;
179  }
180 
181  if(fee != 0){
182  LOG_PRINT_L1("We are migrating to aurelius and this transaction should have zero fee and it doesn't, rejecting.");
183  tvc.m_verification_failed = true;
184  return false;
185  }
186  }else{
187 
188  if(outputs_amount > inputs_amount)
189  {
190  LOG_PRINT_L1("transaction use more ETN than it has: use " << print_etn(outputs_amount) << ", have " << print_etn(inputs_amount));
191  tvc.m_verification_failed = true;
192  tvc.m_overspend = true;
193  return false;
194  }
195  else if(tx.version != 2 && outputs_amount == inputs_amount)
196  {
197 
198  // v1 & v2 tx ins/outs semantics are checked in the same way regardless of our chains height or the network height
199  if(tx.version == 1) {
200  LOG_PRINT_L1("v1 transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
201  tvc.m_verification_failed = true;
202  tvc.m_fee_too_low = true;
203  return false;
204  }
205 
206  // for v3 these are fee paying before the final fork, but feeless afterwards.
207  // the only way of splitting the two up is by checking the destination, because after the final hard fork,
208  // transactions can only go to the bridge (consensus rule elsewhere)
209  if(tx.version == 3){
210  //check to see if all outputs are to the bridge address. if so, waive fee, otherwise if feeless return false
211  std::string portal_address_viewkey_hex_str;
212  std::string portal_address_spendkey_hex_str;
213  if(m_blockchain.get_nettype() == MAINNET){
214  portal_address_viewkey_hex_str = "2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
215  portal_address_spendkey_hex_str = "8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
216  }else{
217  portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
218  portal_address_spendkey_hex_str = "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3"; //
219  }
220  bool is_sc_migration = true;
221  for (auto output: tx.vout){
222  const auto out = boost::get<txout_to_key_public>(output.target);
223  std::string out_spendkey_str = epee::string_tools::pod_to_hex(out.address.m_spend_public_key.data);
224  std::string out_viewkey_str = epee::string_tools::pod_to_hex(out.address.m_view_public_key.data);
225 
226  // If we found an output not going to the bridge, the tx is certainly pre the final hard fork.
227  // so check tx ins/outs semantics here and error/break loop as needed.
228  if(out_spendkey_str != portal_address_spendkey_hex_str || out_viewkey_str != portal_address_viewkey_hex_str){
229  is_sc_migration = false;
230  if(inputs_amount <= outputs_amount){
231  LOG_PRINT_L1("pre smartchain migration version 3 tx with wrong amounts: ins " << print_etn(inputs_amount) << ", outs " << print_etn(outputs_amount) << ", rejected for tx id= "
232  << get_transaction_hash(tx));
233  return false;
234  }else {
235  break; // we only need to check the overall tx once
236  }
237  }
238  }
239 
240  if (is_sc_migration == true && inputs_amount != outputs_amount){
241  LOG_PRINT_L1("version 3 smartchain migration tx should be feeless but has wrong amounts: ins " << print_etn(inputs_amount) << ", outs " << print_etn(outputs_amount) << ", rejected for tx id= "
242  << get_transaction_hash(tx));
243  return false;
244  }
245  }
246  }
247 
248  if(tx.version == 2 && fee != 0) //Assure 0 fee tx v2 (migration tx)
249  {
250  LOG_PRINT_L1("transaction v2 fee is greater than zero, rejecting.");
251  tvc.m_verification_failed = true;
252  return false;
253  }
254 
255  if (tx.version != 2 && !kept_by_block && !m_blockchain.check_fee(tx_weight, fee))
256  {
257  tvc.m_verification_failed = true;
258  tvc.m_fee_too_low = true;
259  return false;
260  }
261  }
262 
263  size_t tx_weight_limit = get_transaction_weight_limit(version);
264  if ((!kept_by_block || version >= HF_VERSION_PER_BYTE_FEE) && tx_weight > tx_weight_limit)
265  {
266  LOG_PRINT_L1("transaction is too heavy: " << tx_weight << " bytes, maximum weight: " << tx_weight_limit);
267  tvc.m_verification_failed = true;
268  tvc.m_too_big = true;
269  return false;
270  }
271 
272  // if the transaction came from a block popped from the chain,
273  // don't check if we have its key images as spent.
274  // TODO: Investigate why not?
275  if(!kept_by_block)
276  {
277  if(tx.version <= 2) {
278  if (key_images_already_spent(tx)) {
279  mark_double_spend_or_nonexistent_utxo(tx);
280  LOG_PRINT_L1("Transaction with id= " << id << " used already spent key images");
281  tvc.m_verification_failed = true;
282  tvc.m_double_spend = true;
283  return false;
284  }
285  }
286  if(tx.version > 2) {
287  if (utxo_nonexistent(tx)) {
288  mark_double_spend_or_nonexistent_utxo(tx);
289  LOG_PRINT_L1("Transaction with id= " << id << " used nonexistent utxos");
290  tvc.m_verification_failed = true;
291  tvc.m_utxo_nonexistent = true;
292  return false;
293  }
294  }
295  }
296 
297  if (!m_blockchain.check_tx_outputs(tx, tvc))
298  {
299  LOG_PRINT_L1("Transaction with id= "<< id << " has at least one invalid output");
300  tvc.m_verification_failed = true;
301  tvc.m_invalid_output = true;
302  return false;
303  }
304 
305  // assume failure during verification steps until success is certain
306  tvc.m_verification_failed = true;
307 
308  time_t receive_time = time(nullptr);
309 
310  crypto::hash max_used_block_id = null_hash;
311  uint64_t max_used_block_height = 0;
313 
314  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);
315 
316  if(tx.version == 3 && m_blockchain.get_current_blockchain_height() > (m_blockchain.get_nettype() == MAINNET ? 1811310 : 1455270)) {
317 
318  //testing
319  //std::string hex_hash = "b166158ee98c5b01252ef6180a1d1ec5f8eced68c947e1a0f2444cf3b9730371";
320  //crypto::hash testing_tx_hash;
321  //epee::string_tools::hex_to_pod(hex_hash, testing_tx_hash);
322  //transaction testing_tx;
323  //m_blockchain.get_db().get_tx(testing_tx_hash, testing_tx);
324 
325  // Block all transactions that don't have valid migration information in the tx extra
326  std::vector<tx_extra_field> tx_extra_fields;
327  //parse_tx_extra(tx.extra, tx_extra_fields);
328  parse_tx_extra(tx.extra, tx_extra_fields);
329  cryptonote::tx_extra_bridge_source_address bridge_source_address;
330  cryptonote::tx_extra_bridge_smartchain_address bridge_smartchain_address;
331  find_tx_extra_field_by_type(tx_extra_fields, bridge_source_address);
332  find_tx_extra_field_by_type(tx_extra_fields, bridge_smartchain_address);
333 
334  address_parse_info parse_info_dummy;
335  if(!cryptonote::get_account_address_from_str(parse_info_dummy, m_blockchain.get_nettype(), bridge_source_address.data)){
336  tvc.m_verification_failed = true;
337  tvc.m_bad_bridge_source_address = true;
338  }
339 
340  // The regular expression pattern for a valid Ethereum address
341  bool valid_smartchain_address = true;
342  std::string string_smartchain_address = bridge_smartchain_address.data;
343  //string_smartchain_address = "0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d";
344  std::regex pattern("^(0x|0X)[a-fA-F0-9]{40}$");
345  if(!std::regex_match(string_smartchain_address, pattern))
346  valid_smartchain_address = false;
347 
348 
349  bool isMixedCase = std::any_of(string_smartchain_address.begin(), string_smartchain_address.end(), [](char c) {
350  return std::isupper(c);
351  }) && std::any_of(string_smartchain_address.begin(), string_smartchain_address.end(), [](char c) {
352  return std::islower(c);
353  });
354 
355  if(isMixedCase && valid_smartchain_address != false){ // if it's mixed case, we have to do extra checks
356  // Convert the address to lowercase for hashing
357  std::string lower_address = string_smartchain_address.substr(2);
358  std::transform(lower_address.begin(), lower_address.end(), lower_address.begin(), ::tolower);
359 
360  unsigned char hashed_lower[32];
361  keccak(reinterpret_cast<const uint8_t *>(lower_address.data()), 40, hashed_lower, 32);
362  std::string address_hash = epee::string_tools::pod_to_hex(hashed_lower); // should be 0x12ed7467c3852e6b2Bd3C22AF694be8DF7637B10.
363 
365  for (size_t i = 0; i < lower_address.length(); i++) {
366  if (std::isdigit(lower_address[i])) {
367  hash += lower_address[i];
368  }
369  else if (address_hash[i] >= '8') {
370  hash += std::toupper(lower_address[i]);
371  }
372  else {
373  hash += lower_address[i];
374  }
375  }
376  std::string checksum = hash.substr(0, 8);
377  for (size_t i = 2; i < checksum.length() + 2; i++) {
378  if (std::islower(string_smartchain_address[i]) && checksum[i - 2] < 'a') {
379  valid_smartchain_address = false;
380  }
381  else if (std::isupper(string_smartchain_address[i]) && checksum[i - 2] < 'A') {
382  char lower_char = std::tolower(string_smartchain_address[i]);
383  if (checksum[i - 2] != lower_char) {
384  valid_smartchain_address = false;
385  }
386  }
387  else if (checksum[i - 2] != string_smartchain_address[i]) {
388  valid_smartchain_address = false;
389  }
390  }
391 
392  } //end of is mixed case
393 
394  if(!valid_smartchain_address){
395  tvc.m_verification_failed = true;
396  tvc.m_bad_bridge_smartchain_address = true;
397  return false;
398  }
399  //BLOCK ALL TX NOT GOING TO THE PORTAL ADDRESS
400  std::string portal_address_viewkey_hex_str;
401  std::string portal_address_spendkey_hex_str;
402  if(m_blockchain.get_nettype() == MAINNET){
403  portal_address_viewkey_hex_str = "2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
404  portal_address_spendkey_hex_str = "8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
405  }else{
406  portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
407  portal_address_spendkey_hex_str = "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3"; //
408  }
409 
410  for (auto output: tx.vout){
411  const auto out = boost::get<txout_to_key_public>(output.target);
412  std::string out_spendkey_str = epee::string_tools::pod_to_hex(out.address.m_spend_public_key.data);
413  std::string out_viewkey_str = epee::string_tools::pod_to_hex(out.address.m_view_public_key.data);
414  if(out_spendkey_str != portal_address_spendkey_hex_str || out_viewkey_str != portal_address_viewkey_hex_str){
415  tvc.m_verification_failed = true;
416  tvc.m_portal_outbound_tx = true;
417  return false;
418  }
419  }
420  }
421 
422  if(!ch_inp_res)
423  {
424  // if the transaction was valid before (kept_by_block), then it
425  // may become valid again, so ignore the failed inputs check.
426  if(kept_by_block)
427  {
428  meta.weight = tx_weight;
429  meta.fee = fee;
430  meta.max_used_block_id = null_hash;
431  meta.max_used_block_height = 0;
432  meta.last_failed_height = 0;
433  meta.last_failed_id = null_hash;
434  meta.kept_by_block = kept_by_block;
435  meta.receive_time = receive_time;
436  meta.last_relayed_time = time(NULL);
437  meta.relayed = relayed;
438  meta.do_not_relay = do_not_relay;
439  meta.double_spend_seen = key_images_already_spent(tx);
440  meta.utxo_nonexistent_seen = utxo_nonexistent(tx);
441  meta.bf_padding = 0;
442  memset(meta.padding, 0, sizeof(meta.padding));
443  try
444  {
445  if (kept_by_block)
446  m_parsed_tx_cache.insert(std::make_pair(id, tx));
447  CRITICAL_REGION_LOCAL1(m_blockchain);
448  LockedTXN lock(m_blockchain);
449  m_blockchain.add_txpool_tx(id, blob, meta);
450  if ((tx.version <= 2 && !insert_key_images(tx, id, kept_by_block)) || (tx.version >= 3 && !insert_utxos(tx, id, kept_by_block)))
451  return false;
452  m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
453  lock.commit();
454  }
455  catch (const std::exception &e)
456  {
457  MERROR("transaction already exists at inserting in memory pool: " << e.what());
458  return false;
459  }
460  tvc.m_verification_impossible = true;
461  tvc.m_added_to_pool = true;
462  }else
463  {
464  LOG_PRINT_L1("tx used wrong inputs, rejected");
465  tvc.m_verification_failed = true;
466  tvc.m_invalid_input = true;
467  return false;
468  }
469  }else
470  {
471  //update transactions container
472  meta.weight = tx_weight;
473  meta.kept_by_block = kept_by_block;
474  meta.fee = fee;
475  meta.max_used_block_id = max_used_block_id;
476  meta.max_used_block_height = max_used_block_height;
477  meta.last_failed_height = 0;
478  meta.last_failed_id = null_hash;
479  meta.receive_time = receive_time;
480  meta.last_relayed_time = time(NULL);
481  meta.relayed = relayed;
482  meta.do_not_relay = do_not_relay;
483  meta.double_spend_seen = false;
484  meta.utxo_nonexistent_seen = false;
485  meta.bf_padding = 0;
486  memset(meta.padding, 0, sizeof(meta.padding));
487 
488  try
489  {
490  if (kept_by_block)
491  m_parsed_tx_cache.insert(std::make_pair(id, tx));
492  CRITICAL_REGION_LOCAL1(m_blockchain);
493  LockedTXN lock(m_blockchain);
494  m_blockchain.remove_txpool_tx(id);
495  m_blockchain.add_txpool_tx(id, blob, meta);
496  if ((tx.version <= 2 && !insert_key_images(tx, id, kept_by_block)) || (tx.version >= 3 && !insert_utxos(tx, id, kept_by_block)))
497  return false;
498  m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
499  lock.commit();
500  }
501  catch (const std::exception &e)
502  {
503  MERROR("internal error: transaction already exists at inserting in memory pool: " << e.what());
504  return false;
505  }
506  tvc.m_added_to_pool = true;
507 
508  if(!do_not_relay)
509  tvc.m_should_be_relayed = true;
510  }
511 
512  tvc.m_verification_failed = false;
513  m_txpool_weight += tx_weight;
514 
515  ++m_cookie;
516 
517  MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)tx_weight));
518 
519  prune(m_txpool_max_weight);
520 
521  return true;
522  }
523  //---------------------------------------------------------------------------------
524  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)
525  {
526  crypto::hash h = null_hash;
527  size_t blob_size = 0;
530  if (bl.size() == 0 || !get_transaction_hash(tx, h))
531  return false;
532  return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, keeped_by_block, relayed, do_not_relay, version);
533  }
534  //---------------------------------------------------------------------------------
536  {
537  CRITICAL_REGION_LOCAL(m_transactions_lock);
538  return m_txpool_weight;
539  }
540  //---------------------------------------------------------------------------------
542  {
543  CRITICAL_REGION_LOCAL(m_transactions_lock);
544  m_txpool_max_weight = bytes;
545  }
546  //---------------------------------------------------------------------------------
547  void tx_memory_pool::prune(size_t bytes)
548  {
549  CRITICAL_REGION_LOCAL(m_transactions_lock);
550  if (bytes == 0)
551  bytes = m_txpool_max_weight;
552  CRITICAL_REGION_LOCAL1(m_blockchain);
553  LockedTXN lock(m_blockchain);
554  bool changed = false;
555 
556  // this will never remove the first one, but we don't care
557  auto it = --m_txs_by_fee_and_receive_time.end();
558  while (it != m_txs_by_fee_and_receive_time.begin())
559  {
560  if (m_txpool_weight <= bytes)
561  break;
562  try
563  {
564  const crypto::hash &txid = it->second;
565  txpool_tx_meta_t meta;
566  if (!m_blockchain.get_txpool_tx_meta(txid, meta))
567  {
568  MERROR("Failed to find tx in txpool");
569  return;
570  }
571  // don't prune the kept_by_block ones, they're likely added because we're adding a block with those
572  if (meta.kept_by_block)
573  {
574  --it;
575  continue;
576  }
577  cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
580  {
581  MERROR("Failed to parse tx from txpool");
582  return;
583  }
584  // remove first, in case this throws, so key images aren't removed
585  MINFO("Pruning tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first);
586  m_blockchain.remove_txpool_tx(txid);
587  m_txpool_weight -= meta.weight;
588  remove_transaction_keyimages(tx, txid);
589  MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first);
590  m_txs_by_fee_and_receive_time.erase(it--);
591  changed = true;
592  }
593  catch (const std::exception &e)
594  {
595  MERROR("Error while pruning txpool: " << e.what());
596  return;
597  }
598  }
599  lock.commit();
600  if (changed)
601  ++m_cookie;
602  if (m_txpool_weight > bytes)
603  MINFO("Pool weight after pruning is larger than limit: " << m_txpool_weight << "/" << bytes);
604  }
605  //---------------------------------------------------------------------------------
606  bool tx_memory_pool::insert_key_images(const transaction_prefix &tx, const crypto::hash &id, bool kept_by_block)
607  {
608  for(const auto& in: tx.vin)
609  {
610  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
611  std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
612  CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block
613  << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
614  << "tx_id=" << id );
615  auto ins_res = kei_image_set.insert(id);
616  CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
617  }
618  ++m_cookie;
619  return true;
620  }
621  //---------------------------------------------------------------------------------
622  bool tx_memory_pool::insert_utxos(const transaction_prefix &tx, const crypto::hash &id, bool kept_by_block)
623  {
624  for(const auto& in: tx.vin)
625  {
626  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, txin, false);
628  std::unordered_set<crypto::hash>& utxo_set = m_spent_utxos[txin_key];
629  CHECK_AND_ASSERT_MES(kept_by_block || utxo_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block
630  << ", utxo_set.size()=" << utxo_set.size() << ENDL << "txin=" << txin_key << ENDL
631  << "tx_id=" << id );
632  auto ins_res = utxo_set.insert(id);
633  CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in utxo set");
634  }
635  ++m_cookie;
636  return true;
637  }
638  //---------------------------------------------------------------------------------
639  //FIXME: Can return early before removal of all of the key images.
640  // At the least, need to make sure that a false return here
641  // is treated properly. Should probably not return early, however.
642  bool tx_memory_pool::remove_transaction_keyimages(const transaction_prefix& tx, const crypto::hash &actual_hash)
643  {
644  CRITICAL_REGION_LOCAL(m_transactions_lock);
645  CRITICAL_REGION_LOCAL1(m_blockchain);
646  // ND: Speedup
647  for(const txin_v& vi: tx.vin)
648  {
649  if(vi.type() == typeid(txin_to_key))
650  {
651  const auto &txin = boost::get<txin_to_key>(vi);
652 
653  auto it = m_spent_key_images.find(txin.k_image);
654  CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << txin.k_image << ENDL
655  << "transaction id = " << actual_hash);
656  std::unordered_set<crypto::hash>& key_image_set = it->second;
657  CHECK_AND_ASSERT_MES(key_image_set.size(), false, "empty key_image set, img=" << txin.k_image << ENDL
658  << "transaction id = " << actual_hash);
659 
660  auto it_in_set = key_image_set.find(actual_hash);
661  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
662  << "transaction id = " << actual_hash);
663  key_image_set.erase(it_in_set);
664  if(!key_image_set.size())
665  {
666  //it is now empty hash container for this key_image
667  m_spent_key_images.erase(it);
668  }
669  }
670  else if (vi.type() == typeid(txin_to_key_public))
671  {
672  const auto &txin = boost::get<txin_to_key_public>(vi);
673 
675 
676  auto it = m_spent_utxos.find(txin_key);
677  CHECK_AND_ASSERT_MES(it != m_spent_utxos.end(), false, "failed to find transaction input in utxos. utxo=" << txin_key << ENDL
678  << "transaction id = " << actual_hash);
679  std::unordered_set<crypto::hash>& utxo_set = it->second;
680  CHECK_AND_ASSERT_MES(utxo_set.size(), false, "empty utxo set, utxo=" << txin_key << ENDL
681  << "transaction id = " << actual_hash);
682 
683  auto it_in_set = utxo_set.find(actual_hash);
684  CHECK_AND_ASSERT_MES(it_in_set != utxo_set.end(), false, "transaction id not found in utxo set, utxo=" << txin_key << ENDL
685  << "transaction id = " << actual_hash);
686  utxo_set.erase(it_in_set);
687  if(!utxo_set.size())
688  {
689  //it is now empty hash container for this key_image
690  m_spent_utxos.erase(it);
691  }
692  }
693  else
694  {
695  return false;
696  }
697  }
698  ++m_cookie;
699  return true;
700  }
701  //---------------------------------------------------------------------------------
702  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)
703  {
704  CRITICAL_REGION_LOCAL(m_transactions_lock);
705  CRITICAL_REGION_LOCAL1(m_blockchain);
706 
707  auto sorted_it = find_tx_in_sorted_container(id);
708 
709  try
710  {
711  LockedTXN lock(m_blockchain);
712  txpool_tx_meta_t meta;
713  if (!m_blockchain.get_txpool_tx_meta(id, meta))
714  {
715  MERROR("Failed to find tx in txpool");
716  return false;
717  }
718  txblob = m_blockchain.get_txpool_tx_blob(id);
719  auto ci = m_parsed_tx_cache.find(id);
720  if (ci != m_parsed_tx_cache.end())
721  {
722  tx = ci->second;
723  }
724  else if (!parse_and_validate_tx_from_blob(txblob, tx))
725  {
726  MERROR("Failed to parse tx from txpool");
727  return false;
728  }
729  else
730  {
731  tx.set_hash(id);
732  }
733  tx_weight = meta.weight;
734  fee = meta.fee;
735  relayed = meta.relayed;
736  do_not_relay = meta.do_not_relay;
737  double_spend_seen = meta.double_spend_seen;
738  nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
739 
740  // remove first, in case this throws, so key images aren't removed
741  m_blockchain.remove_txpool_tx(id);
742  m_txpool_weight -= tx_weight;
743  remove_transaction_keyimages(tx, id);
744  lock.commit();
745  }
746  catch (const std::exception &e)
747  {
748  MERROR("Failed to remove tx from txpool: " << e.what());
749  return false;
750  }
751 
752  if (sorted_it != m_txs_by_fee_and_receive_time.end())
753  m_txs_by_fee_and_receive_time.erase(sorted_it);
754  ++m_cookie;
755  return true;
756  }
757  //---------------------------------------------------------------------------------
759  {
760  m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
761  }
762  //---------------------------------------------------------------------------------
763  sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(const crypto::hash& id) const
764  {
765  return std::find_if( m_txs_by_fee_and_receive_time.begin(), m_txs_by_fee_and_receive_time.end()
766  , [&](const sorted_tx_container::value_type& a){
767  return a.second == id;
768  }
769  );
770  }
771  //---------------------------------------------------------------------------------
772  //TODO: investigate whether boolean return is appropriate
773  bool tx_memory_pool::remove_stuck_transactions()
774  {
775  CRITICAL_REGION_LOCAL(m_transactions_lock);
776  CRITICAL_REGION_LOCAL1(m_blockchain);
777  std::list<std::pair<crypto::hash, uint64_t>> remove;
778  m_blockchain.for_all_txpool_txes([this, &remove](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
779  uint64_t tx_age = time(nullptr) - meta.receive_time;
780  uint32_t mempool_lifetime = m_blockchain.get_mempool_tx_livetime();
781  if((tx_age > mempool_lifetime && !meta.kept_by_block) ||
782  (tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && meta.kept_by_block) )
783  {
784  LOG_PRINT_L1("Tx " << txid << " removed from tx pool due to outdated, age: " << tx_age );
785  auto sorted_it = find_tx_in_sorted_container(txid);
786  if (sorted_it == m_txs_by_fee_and_receive_time.end())
787  {
788  LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
789  }
790  else
791  {
792  m_txs_by_fee_and_receive_time.erase(sorted_it);
793  }
794  m_timed_out_transactions.insert(txid);
795  remove.push_back(std::make_pair(txid, meta.weight));
796  }
797  return true;
798  }, false);
799 
800  if (!remove.empty())
801  {
802  LockedTXN lock(m_blockchain);
803  for (const std::pair<crypto::hash, uint64_t> &entry: remove)
804  {
805  const crypto::hash &txid = entry.first;
806  try
807  {
808  cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
811  {
812  MERROR("Failed to parse tx from txpool");
813  // continue
814  }
815  else
816  {
817  // remove first, so we only remove key images if the tx removal succeeds
818  m_blockchain.remove_txpool_tx(txid);
819  m_txpool_weight -= entry.second;
820  remove_transaction_keyimages(tx, txid);
821  }
822  }
823  catch (const std::exception &e)
824  {
825  MWARNING("Failed to remove stuck transaction: " << txid);
826  // ignore error
827  }
828  }
829  lock.commit();
830  ++m_cookie;
831  }
832  return true;
833  }
834  //---------------------------------------------------------------------------------
835  //TODO: investigate whether boolean return is appropriate
836  bool tx_memory_pool::get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs) const
837  {
838  CRITICAL_REGION_LOCAL(m_transactions_lock);
839  CRITICAL_REGION_LOCAL1(m_blockchain);
840  const uint64_t now = time(NULL);
841  txs.reserve(m_blockchain.get_txpool_tx_count());
842  m_blockchain.for_all_txpool_txes([this, now, &txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
843  // 0 fee transactions are never relayed
844  if(!meta.do_not_relay && now - meta.last_relayed_time > get_relay_delay(now, meta.receive_time))
845  {
846  // if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
847  // mentioned by smooth where nodes would flush txes at slightly different times, causing
848  // flushed txes to be re-added when received from a node which was just about to flush it
849  uint32_t mempool_lifetime = m_blockchain.get_mempool_tx_livetime();
850  uint64_t max_age = meta.kept_by_block ? CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME : mempool_lifetime;
851  if (now - meta.receive_time <= max_age / 2)
852  {
853  try
854  {
855  cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
856  txs.push_back(std::make_pair(txid, bd));
857  }
858  catch (const std::exception &e)
859  {
860  MERROR("Failed to get transaction blob from db");
861  // ignore error
862  }
863  }
864  }
865  return true;
866  }, false);
867  return true;
868  }
869  //---------------------------------------------------------------------------------
870  void tx_memory_pool::set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs)
871  {
872  CRITICAL_REGION_LOCAL(m_transactions_lock);
873  CRITICAL_REGION_LOCAL1(m_blockchain);
874  const time_t now = time(NULL);
875  LockedTXN lock(m_blockchain);
876  for (auto it = txs.begin(); it != txs.end(); ++it)
877  {
878  try
879  {
880  txpool_tx_meta_t meta;
881  if (m_blockchain.get_txpool_tx_meta(it->first, meta))
882  {
883  meta.relayed = true;
884  meta.last_relayed_time = now;
885  m_blockchain.update_txpool_tx(it->first, meta);
886  }
887  }
888  catch (const std::exception &e)
889  {
890  MERROR("Failed to update txpool transaction metadata: " << e.what());
891  // continue
892  }
893  }
894  lock.commit();
895  }
896  //---------------------------------------------------------------------------------
897  size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
898  {
899  CRITICAL_REGION_LOCAL(m_transactions_lock);
900  CRITICAL_REGION_LOCAL1(m_blockchain);
901  return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
902  }
903  //---------------------------------------------------------------------------------
904  void tx_memory_pool::get_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes) const
905  {
906  CRITICAL_REGION_LOCAL(m_transactions_lock);
907  CRITICAL_REGION_LOCAL1(m_blockchain);
908  txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
909  m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
910  transaction tx;
911  if (!parse_and_validate_tx_from_blob(*bd, tx))
912  {
913  MERROR("Failed to parse tx from txpool");
914  // continue
915  return true;
916  }
917  tx.set_hash(txid);
918  txs.push_back(std::move(tx));
919  return true;
920  }, true, include_unrelayed_txes);
921  }
922  //------------------------------------------------------------------
923  void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes) const
924  {
925  CRITICAL_REGION_LOCAL(m_transactions_lock);
926  CRITICAL_REGION_LOCAL1(m_blockchain);
927  txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
928  m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
929  txs.push_back(txid);
930  return true;
931  }, false, include_unrelayed_txes);
932  }
933  //------------------------------------------------------------------
934  void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes) const
935  {
936  CRITICAL_REGION_LOCAL(m_transactions_lock);
937  CRITICAL_REGION_LOCAL1(m_blockchain);
938  const uint64_t now = time(NULL);
939  backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
940  m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
941  backlog.push_back({meta.weight, meta.fee, meta.receive_time - now});
942  return true;
943  }, false, include_unrelayed_txes);
944  }
945  //------------------------------------------------------------------
946  void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes) const
947  {
948  CRITICAL_REGION_LOCAL(m_transactions_lock);
949  CRITICAL_REGION_LOCAL1(m_blockchain);
950  const uint64_t now = time(NULL);
951  std::map<uint64_t, txpool_histo> agebytes;
952  stats.txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
953  std::vector<uint32_t> weights;
954  weights.reserve(stats.txs_total);
955  m_blockchain.for_all_txpool_txes([&stats, &weights, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
956  weights.push_back(meta.weight);
957  stats.bytes_total += meta.weight;
958  if (!stats.bytes_min || meta.weight < stats.bytes_min)
959  stats.bytes_min = meta.weight;
960  if (meta.weight > stats.bytes_max)
961  stats.bytes_max = meta.weight;
962  if (!meta.relayed)
963  stats.num_not_relayed++;
964  stats.fee_total += meta.fee;
965  if (!stats.oldest || meta.receive_time < stats.oldest)
966  stats.oldest = meta.receive_time;
967  if (meta.receive_time < now - 600)
968  stats.num_10m++;
969  if (meta.last_failed_height)
970  stats.num_failing++;
971  uint64_t age = now - meta.receive_time + (now == meta.receive_time);
972  agebytes[age].txs++;
973  agebytes[age].bytes += meta.weight;
974  if (meta.double_spend_seen)
975  ++stats.num_double_spends;
976  if(meta.utxo_nonexistent_seen)
977  ++stats.num_nonexistent_utxos;
978  return true;
979  }, false, include_unrelayed_txes);
980  stats.bytes_med = epee::misc_utils::median(weights);
981  if (stats.txs_total > 1)
982  {
983  /* looking for 98th percentile */
984  size_t end = stats.txs_total * 0.02;
985  uint64_t delta, factor;
986  std::map<uint64_t, txpool_histo>::iterator it, i2;
987  if (end)
988  {
989  /* If enough txs, spread the first 98% of results across
990  * the first 9 bins, drop final 2% in last bin.
991  */
992  it=agebytes.end();
993  for (size_t n=0; n <= end; n++, it--);
994  stats.histo_98pc = it->first;
995  factor = 9;
996  delta = it->first;
997  stats.histo.resize(10);
998  } else
999  {
1000  /* If not enough txs, don't reserve the last slot;
1001  * spread evenly across all 10 bins.
1002  */
1003  stats.histo_98pc = 0;
1004  it = agebytes.end();
1005  factor = stats.txs_total > 9 ? 10 : stats.txs_total;
1006  delta = now - stats.oldest;
1007  stats.histo.resize(factor);
1008  }
1009  if (!delta)
1010  delta = 1;
1011  for (i2 = agebytes.begin(); i2 != it; i2++)
1012  {
1013  size_t i = (i2->first * factor - 1) / delta;
1014  stats.histo[i].txs += i2->second.txs;
1015  stats.histo[i].bytes += i2->second.bytes;
1016  }
1017  for (; i2 != agebytes.end(); i2++)
1018  {
1019  stats.histo[factor].txs += i2->second.txs;
1020  stats.histo[factor].bytes += i2->second.bytes;
1021  }
1022  }
1023  }
1024  //------------------------------------------------------------------
1025  //TODO: investigate whether boolean return is appropriate
1026  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
1027  {
1028  CRITICAL_REGION_LOCAL(m_transactions_lock);
1029  CRITICAL_REGION_LOCAL1(m_blockchain);
1030  tx_infos.reserve(m_blockchain.get_txpool_tx_count());
1031  key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
1032  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){
1033  tx_info txi;
1035  txi.tx_blob = *bd;
1036  transaction tx;
1037  if (!parse_and_validate_tx_from_blob(*bd, tx))
1038  {
1039  MERROR("Failed to parse tx from txpool");
1040  // continue
1041  return true;
1042  }
1043  tx.set_hash(txid);
1044  txi.tx_json = obj_to_json_str(tx);
1045  txi.blob_size = bd->size();
1046  txi.weight = meta.weight;
1047  txi.fee = meta.fee;
1048  txi.kept_by_block = meta.kept_by_block;
1053  // In restricted mode we do not include this data:
1054  txi.receive_time = include_sensitive_data ? meta.receive_time : 0;
1055  txi.relayed = meta.relayed;
1056  // In restricted mode we do not include this data:
1057  txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
1058  txi.do_not_relay = meta.do_not_relay;
1061 
1062  tx_infos.push_back(std::move(txi));
1063  return true;
1064  }, true, include_sensitive_data);
1065 
1066  txpool_tx_meta_t meta;
1067  for (const key_images_container::value_type& kee : m_spent_key_images) {
1068  const crypto::key_image& k_image = kee.first;
1069  const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
1072  for (const crypto::hash& tx_id_hash : kei_image_set)
1073  {
1074  if (!include_sensitive_data)
1075  {
1076  try
1077  {
1078  if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
1079  {
1080  MERROR("Failed to get tx meta from txpool");
1081  return false;
1082  }
1083  if (!meta.relayed)
1084  // Do not include that transaction if in restricted mode and it's not relayed
1085  continue;
1086  }
1087  catch (const std::exception &e)
1088  {
1089  MERROR("Failed to get tx meta from txpool: " << e.what());
1090  return false;
1091  }
1092  }
1093  ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
1094  }
1095  // Only return key images for which we have at least one tx that we can show for them
1096  if (!ki.txs_hashes.empty())
1097  key_image_infos.push_back(ki);
1098  }
1099  return true;
1100  }
1101  //---------------------------------------------------------------------------------
1102  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
1103  {
1104  CRITICAL_REGION_LOCAL(m_transactions_lock);
1105  CRITICAL_REGION_LOCAL1(m_blockchain);
1106  tx_infos.reserve(m_blockchain.get_txpool_tx_count());
1107  key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
1108  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){
1110  txi.tx_hash = txid;
1111  if (!parse_and_validate_tx_from_blob(*bd, txi.tx))
1112  {
1113  MERROR("Failed to parse tx from txpool");
1114  // continue
1115  return true;
1116  }
1117  txi.tx.set_hash(txid);
1118  txi.blob_size = bd->size();
1119  txi.weight = meta.weight;
1120  txi.fee = meta.fee;
1121  txi.kept_by_block = meta.kept_by_block;
1126  txi.receive_time = meta.receive_time;
1127  txi.relayed = meta.relayed;
1129  txi.do_not_relay = meta.do_not_relay;
1132 
1133  tx_infos.push_back(txi);
1134  return true;
1135  }, true, false);
1136 
1137  for (const key_images_container::value_type& kee : m_spent_key_images) {
1138  std::vector<crypto::hash> tx_hashes;
1139  const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
1140  for (const crypto::hash& tx_id_hash : kei_image_set)
1141  {
1142  tx_hashes.push_back(tx_id_hash);
1143  }
1144 
1145  const crypto::key_image& k_image = kee.first;
1146  key_image_infos[k_image] = std::move(tx_hashes);
1147  }
1148  return true;
1149  }
1150  //---------------------------------------------------------------------------------
1151  bool tx_memory_pool::check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool> spent) const
1152  {
1153  CRITICAL_REGION_LOCAL(m_transactions_lock);
1154  CRITICAL_REGION_LOCAL1(m_blockchain);
1155 
1156  spent.clear();
1157 
1158  for (const auto& image : key_images)
1159  {
1160  spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ? false : true);
1161  }
1162 
1163  return true;
1164  }
1165  //---------------------------------------------------------------------------------
1167  {
1168  CRITICAL_REGION_LOCAL(m_transactions_lock);
1169  CRITICAL_REGION_LOCAL1(m_blockchain);
1170  try
1171  {
1172  return m_blockchain.get_txpool_tx_blob(id, txblob);
1173  }
1174  catch (const std::exception &e)
1175  {
1176  return false;
1177  }
1178  }
1179  //---------------------------------------------------------------------------------
1180  bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id)
1181  {
1182  CRITICAL_REGION_LOCAL(m_transactions_lock);
1183  m_input_cache.clear();
1184  m_parsed_tx_cache.clear();
1185  return true;
1186  }
1187  //---------------------------------------------------------------------------------
1188  bool tx_memory_pool::on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id)
1189  {
1190  CRITICAL_REGION_LOCAL(m_transactions_lock);
1191  m_input_cache.clear();
1192  m_parsed_tx_cache.clear();
1193  return true;
1194  }
1195  //---------------------------------------------------------------------------------
1197  {
1198  CRITICAL_REGION_LOCAL(m_transactions_lock);
1199  CRITICAL_REGION_LOCAL1(m_blockchain);
1200  return m_blockchain.get_db().txpool_has_tx(id);
1201  }
1202 
1203  //---------------------------------------------------------------------------------
1204  bool tx_memory_pool::key_images_already_spent(const transaction& tx) const
1205  {
1206  CRITICAL_REGION_LOCAL(m_transactions_lock);
1207  CRITICAL_REGION_LOCAL1(m_blockchain);
1208  for(const auto& in: tx.vin)
1209  {
1210  if(in.type() == typeid(txin_to_key))
1211  {
1212  const auto &tokey_in = boost::get<txin_to_key>(in);
1213  if(have_tx_keyimg_as_spent(tokey_in.k_image)) // key_image
1214  return true;
1215  }
1216  }
1217  return false;
1218  }
1219 
1221  CRITICAL_REGION_LOCAL(m_transactions_lock);
1222  CRITICAL_REGION_LOCAL1(m_blockchain);
1223  return have_tx_utxo_as_spent(in);
1224  }
1225  //---------------------------------------------------------------------------------
1226  bool tx_memory_pool::utxo_nonexistent(const transaction& tx) const
1227  {
1228  CRITICAL_REGION_LOCAL(m_transactions_lock);
1229  CRITICAL_REGION_LOCAL1(m_blockchain);
1230  for(const auto& in: tx.vin)
1231  {
1232  if (in.type() == typeid(txin_to_key_public))
1233  {
1234  const auto &tokey_in = boost::get<txin_to_key_public>(in);
1235  if(have_tx_utxo_as_spent(tokey_in)) // UTXO
1236  return true;
1237  }
1238  }
1239  return false;
1240  }
1241  //---------------------------------------------------------------------------------
1242  bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const
1243  {
1244  CRITICAL_REGION_LOCAL(m_transactions_lock);
1245  return m_spent_key_images.end() != m_spent_key_images.find(key_im);
1246  }
1247  //---------------------------------------------------------------------------------
1248  bool tx_memory_pool::have_tx_utxo_as_spent(const txin_to_key_public& in) const
1249  {
1250  CRITICAL_REGION_LOCAL(m_transactions_lock);
1252  return m_spent_utxos.end() != m_spent_utxos.find(txin_key);
1253  }
1254  //---------------------------------------------------------------------------------
1256  {
1257  m_transactions_lock.lock();
1258  }
1259  //---------------------------------------------------------------------------------
1261  {
1262  m_transactions_lock.unlock();
1263  }
1264  //---------------------------------------------------------------------------------
1265  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
1266  {
1267  if (!kept_by_block)
1268  {
1269  const std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>>::const_iterator i = m_input_cache.find(txid);
1270  if (i != m_input_cache.end())
1271  {
1272  max_used_block_height = std::get<2>(i->second);
1273  max_used_block_id = std::get<3>(i->second);
1274  tvc = std::get<1>(i->second);
1275  return std::get<0>(i->second);
1276  }
1277  }
1278  bool ret = m_blockchain.check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, kept_by_block);
1279  if (!kept_by_block)
1280  m_input_cache.insert(std::make_pair(txid, std::make_tuple(ret, tvc, max_used_block_height, max_used_block_id)));
1281  return ret;
1282  }
1283  //---------------------------------------------------------------------------------
1284  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
1285  {
1286  struct transction_parser
1287  {
1288  transction_parser(const cryptonote::blobdata &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
1289  cryptonote::transaction &operator()()
1290  {
1291  if (!parsed)
1292  {
1293  if (!parse_and_validate_tx_from_blob(txblob, tx))
1294  throw std::runtime_error("failed to parse transaction blob");
1295  tx.set_hash(txid);
1296  parsed = true;
1297  }
1298  return tx;
1299  }
1300  const cryptonote::blobdata &txblob;
1301  const crypto::hash &txid;
1302  transaction &tx;
1303  bool parsed;
1304  } lazy_tx(txblob, txid, tx);
1305 
1306  //not the best implementation at this time, sorry :(
1307  //check is ring_signature already checked ?
1308  if(txd.max_used_block_id == null_hash)
1309  {//not checked, lets try to check
1310 
1311  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))
1312  return false;//we already sure that this tx is broken for this height
1313 
1314  tx_verification_context tvc;
1315  if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
1316  {
1317  txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
1318  txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
1319  return false;
1320  }
1321  }else
1322  {
1323  if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height())
1324  return false;
1325  if(true)
1326  {
1327  //if we already failed on this height and id, skip actual ring signature check
1328  if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
1329  return false;
1330  //check ring signature again, it is possible (with very small chance) that this transaction become again valid
1331  tx_verification_context tvc;
1332  if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
1333  {
1334  txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
1335  txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
1336  return false;
1337  }
1338  }
1339  }
1340 
1341  //if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure
1342  if(tx.version < 3 && m_blockchain.key_images_already_spent(lazy_tx()))
1343  {
1344  txd.double_spend_seen = true;
1345  return false;
1346  }
1347  if(tx.version > 2 && m_blockchain.utxo_nonexistent(lazy_tx()))
1348  {
1349  txd.utxo_nonexistent_seen = true;
1350  return false;
1351  }
1352 
1353  //transaction is ok.
1354  return true;
1355  }
1356  //---------------------------------------------------------------------------------
1357  bool tx_memory_pool::have_key_images(const std::unordered_set<crypto::key_image>& k_images, const transaction_prefix& tx)
1358  {
1359  for(size_t i = 0; i!= tx.vin.size(); i++)
1360  {
1361  if(tx.vin[i].type() == typeid(txin_to_key))
1362  {
1363  const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1364  if(k_images.count(itk.k_image))
1365  return true;
1366  }
1367  }
1368  return false;
1369  }
1370  //---------------------------------------------------------------------------------
1371  bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images, const transaction_prefix& tx)
1372  {
1373  for(size_t i = 0; i!= tx.vin.size(); i++)
1374  {
1375  if(tx.vin[i].type() == typeid(txin_to_key))
1376  {
1377  const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1378  auto i_res = k_images.insert(itk.k_image);
1379  CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image);
1380  }
1381  }
1382  return true;
1383  }
1384  //---------------------------------------------------------------------------------
1385  bool tx_memory_pool::have_utxos(const std::unordered_set<std::string>& utxos, const transaction_prefix& tx)
1386  {
1387  for(size_t i = 0; i!= tx.vin.size(); i++)
1388  {
1389  if(tx.vin[i].type() == typeid(txin_to_key_public))
1390  {
1391  const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1393  if(utxos.count(txin_key))
1394  return true;
1395  }
1396 
1397  }
1398  return false;
1399  }
1400  //---------------------------------------------------------------------------------
1401  bool tx_memory_pool::append_utxos(std::unordered_set<std::string>& utxos, const transaction_prefix& tx)
1402  {
1403  for(size_t i = 0; i!= tx.vin.size(); i++)
1404  {
1405  if(tx.vin[i].type() == typeid(txin_to_key_public))
1406  {
1407  const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1408 
1410  auto i_res = utxos.insert(txin_key);
1411  CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: utxo pool cache - inserted duplicate image in set: " << txin_key);
1412  }
1413  }
1414  return true;
1415  }
1416  //---------------------------------------------------------------------------------
1417  void tx_memory_pool::mark_double_spend_or_nonexistent_utxo(const transaction &tx)
1418  {
1419  CRITICAL_REGION_LOCAL(m_transactions_lock);
1420  CRITICAL_REGION_LOCAL1(m_blockchain);
1421  bool changed = false;
1422  LockedTXN lock(m_blockchain);
1423  for(size_t i = 0; i!= tx.vin.size(); i++)
1424  {
1425  if(tx.vin[i].type() == typeid(txin_to_key))
1426  {
1427  CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, void());
1428  const key_images_container::const_iterator it = m_spent_key_images.find(itk.k_image);
1429  if (it != m_spent_key_images.end())
1430  {
1431  for (const crypto::hash &txid: it->second)
1432  {
1433  txpool_tx_meta_t meta;
1434  if (!m_blockchain.get_txpool_tx_meta(txid, meta))
1435  {
1436  MERROR("Failed to find tx meta in txpool");
1437  // continue, not fatal
1438  continue;
1439  }
1440  if (!meta.double_spend_seen)
1441  {
1442  MDEBUG("Marking " << txid << " as double spending " << itk.k_image);
1443  meta.double_spend_seen = true;
1444  changed = true;
1445  try
1446  {
1447  m_blockchain.update_txpool_tx(txid, meta);
1448  }
1449  catch (const std::exception &e)
1450  {
1451  MERROR("Failed to update tx meta: " << e.what());
1452  // continue, not fatal
1453  }
1454  }
1455  }
1456  }
1457  }
1458  else if (tx.vin[i].type() == typeid(txin_to_key_public))
1459  {
1460  CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key_public, itk, void());
1462  const utxos_container::const_iterator it = m_spent_utxos.find(txin_key);
1463  if (it != m_spent_utxos.end())
1464  {
1465  for (const crypto::hash &txid: it->second)
1466  {
1467  txpool_tx_meta_t meta;
1468  if (!m_blockchain.get_txpool_tx_meta(txid, meta))
1469  {
1470  MERROR("Failed to find tx meta in txpool");
1471  // continue, not fatal
1472  continue;
1473  }
1474  if (!meta.double_spend_seen)
1475  {
1476  MDEBUG("Marking " << txid << " as double spending " << txin_key);
1477  meta.utxo_nonexistent_seen = true;
1478  changed = true;
1479  try
1480  {
1481  m_blockchain.update_txpool_tx(txid, meta);
1482  }
1483  catch (const std::exception &e)
1484  {
1485  MERROR("Failed to update tx meta: " << e.what());
1486  // continue, not fatal
1487  }
1488  }
1489  }
1490  }
1491  }
1492  else
1493  {
1494  return;
1495  }
1496  }
1497  lock.commit();
1498  if (changed)
1499  ++m_cookie;
1500  }
1501  //---------------------------------------------------------------------------------
1502  std::string tx_memory_pool::print_pool(bool short_format) const
1503  {
1504  std::stringstream ss;
1505  CRITICAL_REGION_LOCAL(m_transactions_lock);
1506  CRITICAL_REGION_LOCAL1(m_blockchain);
1507  m_blockchain.for_all_txpool_txes([&ss, short_format](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *txblob) {
1508  ss << "id: " << txid << std::endl;
1509  if (!short_format) {
1511  if (!parse_and_validate_tx_from_blob(*txblob, tx))
1512  {
1513  MERROR("Failed to parse tx from txpool");
1514  return true; // continue
1515  }
1516  ss << obj_to_json_str(tx) << std::endl;
1517  }
1518  ss << "blob_size: " << (short_format ? "-" : std::to_string(txblob->size())) << std::endl
1519  << "weight: " << meta.weight << std::endl
1520  << "fee: " << print_etn(meta.fee) << std::endl
1521  << "kept_by_block: " << (meta.kept_by_block ? 'T' : 'F') << std::endl
1522  << "double_spend_seen: " << (meta.double_spend_seen ? 'T' : 'F') << std::endl
1523  << "nonexistent_utxo_seen: " << (meta.utxo_nonexistent_seen ? 'T' : 'F') << std::endl
1524  << "max_used_block_height: " << meta.max_used_block_height << std::endl
1525  << "max_used_block_id: " << meta.max_used_block_id << std::endl
1526  << "last_failed_height: " << meta.last_failed_height << std::endl
1527  << "last_failed_id: " << meta.last_failed_id << std::endl;
1528  return true;
1529  }, !short_format);
1530 
1531  return ss.str();
1532  }
1533  //---------------------------------------------------------------------------------
1534  //TODO: investigate whether boolean return is appropriate
1535  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)
1536  {
1537  CRITICAL_REGION_LOCAL(m_transactions_lock);
1538  CRITICAL_REGION_LOCAL1(m_blockchain);
1539 
1540  uint64_t best_coinbase = 0, coinbase = 0;
1541  total_weight = 0;
1542  fee = 0;
1543 
1544  //baseline empty block
1545  get_block_reward(median_weight, total_weight, already_generated_coins, best_coinbase, version, m_blockchain.get_current_blockchain_height(), m_blockchain.get_nettype());
1546 
1547 
1548  size_t max_total_weight_pre_v5 = (130 * median_weight) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
1549  size_t max_total_weight_v5 = 2 * median_weight - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
1550  size_t max_total_weight = version >= 5 ? max_total_weight_v5 : max_total_weight_pre_v5;
1551  std::unordered_set<crypto::key_image> k_images;
1552  std::unordered_set<std::string> utxos;
1553 
1554  LOG_PRINT_L2("Filling block template, median weight " << median_weight << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
1555 
1556  LockedTXN lock(m_blockchain);
1557 
1558  auto sorted_it = m_txs_by_fee_and_receive_time.begin();
1559  for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
1560  {
1561  txpool_tx_meta_t meta;
1562  if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
1563  {
1564  MERROR(" failed to find tx meta");
1565  continue;
1566  }
1567  LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_etn(best_coinbase));
1568 
1569  // Can not exceed maximum block weight
1570  if (max_total_weight < total_weight + meta.weight)
1571  {
1572  LOG_PRINT_L2(" would exceed maximum block weight");
1573  continue;
1574  }
1575 
1576  // start using the optimal filling algorithm from v5
1577  if (version >= 5)
1578  {
1579  // If we're getting lower coinbase tx,
1580  // stop including more tx
1581  uint64_t block_reward;
1582  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()))
1583  {
1584  LOG_PRINT_L2(" would exceed maximum block weight");
1585  continue;
1586  }
1587  coinbase = block_reward + fee + meta.fee;
1588  if (coinbase < template_accept_threshold(best_coinbase))
1589  {
1590  LOG_PRINT_L2(" would decrease coinbase to " << print_etn(coinbase));
1591  continue;
1592  }
1593  }
1594  else
1595  {
1596  // If we've exceeded the penalty free weight,
1597  // stop including more tx
1598  if (total_weight > median_weight)
1599  {
1600  LOG_PRINT_L2(" would exceed median block weight");
1601  break;
1602  }
1603  }
1604 
1605  cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second);
1607 
1608  // Skip transactions that are not ready to be
1609  // included into the blockchain or that are
1610  // missing key images
1611  const cryptonote::txpool_tx_meta_t original_meta = meta;
1612  bool ready = false;
1613  try
1614  {
1615  ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
1616  }
1617  catch (const std::exception &e)
1618  {
1619  MERROR("Failed to check transaction readiness: " << e.what());
1620  // continue, not fatal
1621  }
1622  if (memcmp(&original_meta, &meta, sizeof(meta)))
1623  {
1624  try
1625  {
1626  m_blockchain.update_txpool_tx(sorted_it->second, meta);
1627  }
1628  catch (const std::exception &e)
1629  {
1630  MERROR("Failed to update tx meta: " << e.what());
1631  // continue, not fatal
1632  }
1633  }
1634  if (!ready)
1635  {
1636  LOG_PRINT_L2(" not ready to go");
1637  continue;
1638  }
1639  if (have_key_images(k_images, tx))
1640  {
1641  LOG_PRINT_L2(" key images already seen");
1642  continue;
1643  }
1644  if (have_utxos(utxos, tx))
1645  {
1646  LOG_PRINT_L2(" utxos already seen");
1647  continue;
1648  }
1649 
1650  bl.tx_hashes.push_back(sorted_it->second);
1651  total_weight += meta.weight;
1652  fee += meta.fee;
1653  best_coinbase = coinbase;
1654  append_key_images(k_images, tx);
1655  append_utxos(utxos, tx);
1656  LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_etn(best_coinbase));
1657  }
1658  lock.commit();
1659 
1660  expected_reward = best_coinbase;
1661  LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight "
1662  << total_weight << "/" << max_total_weight << ", coinbase " << print_etn(best_coinbase)
1663  << " (including " << print_etn(fee) << " in fees)");
1664  return true;
1665  }
1666  //---------------------------------------------------------------------------------
1668  {
1669  CRITICAL_REGION_LOCAL(m_transactions_lock);
1670  CRITICAL_REGION_LOCAL1(m_blockchain);
1671  size_t tx_weight_limit = get_transaction_weight_limit(version);
1672  std::unordered_set<crypto::hash> remove;
1673 
1674  m_txpool_weight = 0;
1675  m_blockchain.for_all_txpool_txes([this, &remove, tx_weight_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
1676  m_txpool_weight += meta.weight;
1677  if (meta.weight > tx_weight_limit) {
1678  LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.weight << " bytes), removing it from pool");
1679  remove.insert(txid);
1680  }
1681  else if (m_blockchain.have_tx(txid)) {
1682  LOG_PRINT_L1("Transaction " << txid << " is in the blockchain, removing it from pool");
1683  remove.insert(txid);
1684  }
1685  return true;
1686  }, false);
1687 
1688  size_t n_removed = 0;
1689  if (!remove.empty())
1690  {
1691  LockedTXN lock(m_blockchain);
1692  for (const crypto::hash &txid: remove)
1693  {
1694  try
1695  {
1696  cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
1698  if (!parse_and_validate_tx_from_blob(txblob, tx))
1699  {
1700  MERROR("Failed to parse tx from txpool");
1701  continue;
1702  }
1703  // remove tx from db first
1704  m_blockchain.remove_txpool_tx(txid);
1705  m_txpool_weight -= get_transaction_weight(tx, txblob.size());
1706  remove_transaction_keyimages(tx, txid);
1707  auto sorted_it = find_tx_in_sorted_container(txid);
1708  if (sorted_it == m_txs_by_fee_and_receive_time.end())
1709  {
1710  LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
1711  }
1712  else
1713  {
1714  m_txs_by_fee_and_receive_time.erase(sorted_it);
1715  }
1716  ++n_removed;
1717  }
1718  catch (const std::exception &e)
1719  {
1720  MERROR("Failed to remove invalid tx from pool");
1721  // continue
1722  }
1723  }
1724  lock.commit();
1725  }
1726  if (n_removed > 0)
1727  ++m_cookie;
1728  return n_removed;
1729  }
1730  //---------------------------------------------------------------------------------
1731  bool tx_memory_pool::init(size_t max_txpool_weight)
1732  {
1733  CRITICAL_REGION_LOCAL(m_transactions_lock);
1734  CRITICAL_REGION_LOCAL1(m_blockchain);
1735 
1736  m_txpool_max_weight = max_txpool_weight ? max_txpool_weight : DEFAULT_TXPOOL_MAX_WEIGHT;
1737  m_txs_by_fee_and_receive_time.clear();
1738  m_spent_key_images.clear();
1739  m_spent_utxos.clear();
1740  m_txpool_weight = 0;
1741  std::vector<crypto::hash> remove;
1742 
1743  // first add the not kept by block, then the kept by block,
1744  // to avoid rejection due to key image collision
1745  for (int pass = 0; pass < 2; ++pass)
1746  {
1747  const bool kept = pass == 1;
1748  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) {
1749  if (!!kept != !!meta.kept_by_block)
1750  return true;
1753  {
1754  MWARNING("Failed to parse tx from txpool, removing");
1755  remove.push_back(txid);
1756  return true;
1757  }
1758  if (tx.version <= 2 && !insert_key_images(tx, txid, meta.kept_by_block))
1759  {
1760  MFATAL("Failed to insert key images from txpool tx");
1761  return false;
1762  }
1763  if (tx.version >= 3 && !insert_utxos(tx, txid, meta.kept_by_block))
1764  {
1765  MFATAL("Failed to insert utxos from txpool tx");
1766  return false;
1767  }
1768  m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.weight, meta.receive_time), txid);
1769  m_txpool_weight += meta.weight;
1770  return true;
1771  }, true);
1772  if (!r)
1773  return false;
1774  }
1775  if (!remove.empty())
1776  {
1777  LockedTXN lock(m_blockchain);
1778  for (const auto &txid: remove)
1779  {
1780  try
1781  {
1782  m_blockchain.remove_txpool_tx(txid);
1783  }
1784  catch (const std::exception &e)
1785  {
1786  MWARNING("Failed to remove corrupt transaction: " << txid);
1787  // ignore error
1788  }
1789  }
1790  lock.commit();
1791  }
1792 
1793  m_cookie = 0;
1794 
1795  // Ignore deserialization error
1796  return true;
1797  }
1798 
1799  //---------------------------------------------------------------------------------
1801  {
1802  return true;
1803  }
1804 }
void on_idle()
action to take periodically
Definition: tx_pool.cpp:758
#define CRITICAL_REGION_LOCAL1(x)
Definition: syncobj.h:230
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
#define MERROR(x)
Definition: misc_log_ex.h:73
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
std::vector< crypto::hash > tx_hashes
#define MINFO(x)
Definition: misc_log_ex.h:75
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:122
bool check_outs_valid(const transaction &tx)
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
#define PERF_TIMER(name)
Definition: perf_timer.h:82
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
#define MFATAL(x)
Definition: misc_log_ex.h:72
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val)
::std::string string
Definition: gtest-port.h:1097
uint64_t get_outs_etn_amount(const transaction &tx)
bool utxo_nonexistent(const transaction &tx) const
check if any utxo in a transaction has already been spent using the tx (v3 tx onwards) ...
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME
void set_hash(const crypto::hash &h)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
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:904
key commit(etn_amount amount, const key &mask)
Definition: rctOps.cpp:336
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
size_t get_txpool_weight() const
get the cumulative txpool weight in bytes
Definition: tx_pool.cpp:535
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:923
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)
bool parse_and_validate_tx_prefix_from_blob(const blobdata &tx_blob, transaction_prefix &tx)
crypto namespace.
Definition: crypto.cpp:58
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 remove_txpool_tx(const crypto::hash &txid)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
Definition: blockchain.cpp:322
bool key_images_already_spent(const transaction &tx) const
check if any key image in a transaction has already been spent
#define DEFAULT_TXPOOL_MAX_WEIGHT
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta)
unsigned char uint8_t
Definition: stdint.h:124
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
size_t get_transactions_count(bool include_unrelayed_txes=true) const
get the total number of transactions in the pool
Definition: tx_pool.cpp:897
cryptonote::transaction tx
std::unordered_map< crypto::key_image, std::vector< crypto::hash > > key_images_with_tx_hashes
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE
tuple make_tuple()
Definition: gtest-tuple.h:675
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:702
std::vector< uint8_t > extra
#define MDEBUG(x)
Definition: misc_log_ex.h:76
bool init(size_t max_txpool_weight=0)
loads pool state (if any) from disk, and initializes pool
Definition: tx_pool.cpp:1731
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
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:1180
std::vector< txpool_histo > histo
size_t validate(uint8_t version)
remove transactions from the pool which are no longer valid
Definition: tx_pool.cpp:1667
time_t time
Definition: blockchain.cpp:93
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
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&#39;s inputs
unsigned int uint32_t
Definition: stdint.h:126
uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) const
bool check_inputs_types_supported(const transaction &tx)
std::string obj_to_json_str(T &obj)
unsigned __int64 uint64_t
Definition: stdint.h:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
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:870
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
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:1026
#define false
Definition: stdbool.h:38
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:934
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
version
Supported socks variants.
Definition: socks.h:57
#define MWARNING(x)
Definition: misc_log_ex.h:74
const BlockchainDB & get_db() const
get a reference to the BlockchainDB in use by Blockchain
Definition: blockchain.h:963
bool check_fee(size_t tx_weight, uint64_t fee) const
validate a transaction&#39;s fee
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:1151
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
std::string blobdata
Definition: blobdatatype.h:39
type_vec_type median(std::vector< type_vec_type > &v)
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block&#39;s hash given a height
Definition: blockchain.cpp:901
uint32_t get_mempool_tx_livetime() const
void unlock() const
unlocks the transaction pool
Definition: tx_pool.cpp:1260
bool deinit()
attempts to save the transaction pool state to disk
Definition: tx_pool.cpp:1800
const T & move(const T &t)
Definition: gtest-port.h:1317
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
Definition: blockchain.cpp:167
#define ENDL
Definition: misc_log_ex.h:149
bool get_transaction(const crypto::hash &h, cryptonote::blobdata &txblob) const
get a specific transaction from the pool
Definition: tx_pool.cpp:1166
std::string buff_to_hex_nodelimer(const std::string &src)
Definition: string_tools.h:87
POD_CLASS key_image
Definition: crypto.h:102
a struct containing txpool per transaction metadata
void set_txpool_max_weight(size_t bytes)
set the max cumulative txpool weight in bytes
Definition: tx_pool.cpp:541
crypto::hash get_transaction_hash(const transaction &t)
bool have_tx(const crypto::hash &id) const
checks if the pool has a transaction with the given hash
Definition: tx_pool.cpp:1196
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
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:1535
network_type get_nettype() const
get blockchain nettype
Definition: blockchain.h:1073
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
bool utxo_spent_in_pool(const txin_to_key_public &in) const
get a summary statistics of all transaction hashes in the pool
Definition: tx_pool.cpp:1220
DISABLE_VS_WARNINGS(4244 4345 4503) using namespace crypto
POD_CLASS hash
Definition: hash.h:50
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:1188
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)
std::string to_string(t_connection_type type)
else if(0==res)
bool check_tx_outputs(const transaction &tx, tx_verification_context &tvc)
check that a transaction&#39;s outputs conform to current standards
void lock() const
locks the transaction pool
Definition: tx_pool.cpp:1255
#define HF_VERSION_PER_BYTE_FEE
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:946
virtual bool txpool_has_tx(const crypto::hash &txid) const =0
check whether a txid is in the txpool
bool do_call(functor_t functr)
Definition: math_helper.h:263
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta)
bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const
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:1102
std::string print_pool(bool short_format) const
get a string containing human-readable pool information
Definition: tx_pool.cpp:1502
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:836