33 #include <boost/filesystem.hpp>
34 #include <unordered_set>
51 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
52 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "txpool"
67 time_t
const MIN_RELAY_TIME = (60 * 5);
68 time_t
const MAX_RELAY_TIME = (60 * 60 * 4);
69 float const ACCEPT_THRESHOLD = 1.0f;
72 uint64_t get_relay_delay(time_t now, time_t received)
74 time_t d = (now - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME;
75 if (d > MAX_RELAY_TIME)
82 return amount * ACCEPT_THRESHOLD;
100 LockedTXN(Blockchain &b): m_blockchain(b), m_batch(
false), m_active(
false) {
101 m_batch = m_blockchain.get_db().batch_start();
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(); }
108 Blockchain &m_blockchain;
136 if (!kept_by_block && m_timed_out_transactions.find(
id) != m_timed_out_transactions.end())
169 if(outputs_amount > inputs_amount)
176 else if(tx.
version != 2 && outputs_amount == inputs_amount)
178 LOG_PRINT_L1(
"transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
184 fee = inputs_amount - outputs_amount;
186 if(tx.
version == 2 && fee != 0)
188 LOG_PRINT_L1(
"transaction v2 fee is greater than zero, rejecting.");
193 if (tx.
version != 2 && !kept_by_block && !m_blockchain.
check_fee(tx_weight, fee))
200 size_t tx_weight_limit = get_transaction_weight_limit(
version);
203 LOG_PRINT_L1(
"transaction is too heavy: " << tx_weight <<
" bytes, maximum weight: " << tx_weight_limit);
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");
224 if (utxo_nonexistent(tx)) {
225 mark_double_spend_or_nonexistent_utxo(tx);
226 LOG_PRINT_L1(
"Transaction with id= " <<
id <<
" used nonexistent utxos");
236 LOG_PRINT_L1(
"Transaction with id= "<<
id <<
" has at least one invalid output");
245 time_t receive_time =
time(
nullptr);
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);
275 m_parsed_tx_cache.insert(std::make_pair(
id, tx));
277 LockedTXN
lock(m_blockchain);
279 if ((tx.
version <= 2 && !insert_key_images(tx,
id, kept_by_block)) || (tx.
version >= 3 && !insert_utxos(tx,
id, kept_by_block)))
281 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (
double)tx_weight, receive_time),
id);
284 catch (
const std::exception &e)
286 MERROR(
"transaction already exists at inserting in memory pool: " << e.what());
320 m_parsed_tx_cache.insert(std::make_pair(
id, tx));
322 LockedTXN
lock(m_blockchain);
325 if ((tx.
version <= 2 && !insert_key_images(tx,
id, kept_by_block)) || (tx.
version >= 3 && !insert_utxos(tx,
id, kept_by_block)))
327 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (
double)tx_weight, receive_time),
id);
330 catch (
const std::exception &e)
332 MERROR(
"internal error: transaction already exists at inserting in memory pool: " << e.what());
342 m_txpool_weight += tx_weight;
346 MINFO(
"Transaction added to pool: txid " <<
id <<
" weight: " << tx_weight <<
" fee/byte: " << (fee / (
double)tx_weight));
348 prune(m_txpool_max_weight);
356 size_t blob_size = 0;
367 return m_txpool_weight;
373 m_txpool_max_weight = bytes;
376 void tx_memory_pool::prune(
size_t bytes)
380 bytes = m_txpool_max_weight;
382 LockedTXN
lock(m_blockchain);
383 bool changed =
false;
386 auto it = --m_txs_by_fee_and_receive_time.end();
387 while (it != m_txs_by_fee_and_receive_time.begin())
389 if (m_txpool_weight <= bytes)
397 MERROR(
"Failed to find tx in txpool");
410 MERROR(
"Failed to parse tx from txpool");
414 MINFO(
"Pruning tx " << txid <<
" from txpool: weight: " << meta.
weight <<
", fee/byte: " << it->first.first);
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--);
422 catch (
const std::exception &e)
424 MERROR(
"Error while pruning txpool: " << e.what());
431 if (m_txpool_weight > bytes)
432 MINFO(
"Pool weight after pruning is larger than limit: " << m_txpool_weight <<
"/" << bytes);
435 bool tx_memory_pool::insert_key_images(
const transaction_prefix &tx,
const crypto::hash &
id,
bool kept_by_block)
437 for(
const auto& in: tx.vin)
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
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");
451 bool tx_memory_pool::insert_utxos(
const transaction_prefix &tx,
const crypto::hash &
id,
bool kept_by_block)
453 for(
const auto& in: tx.vin)
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
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");
471 bool tx_memory_pool::remove_transaction_keyimages(
const transaction_prefix& tx,
const crypto::hash &actual_hash)
476 for(
const txin_v& vi: tx.vin)
478 if(vi.type() ==
typeid(txin_to_key))
480 const auto &txin = boost::get<txin_to_key>(vi);
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;
487 <<
"transaction id = " << actual_hash);
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())
496 m_spent_key_images.erase(it);
499 else if (vi.type() ==
typeid(txin_to_key_public))
501 const auto &txin = boost::get<txin_to_key_public>(vi);
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;
510 <<
"transaction id = " << actual_hash);
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);
519 m_spent_utxos.erase(it);
536 auto sorted_it = find_tx_in_sorted_container(
id);
540 LockedTXN
lock(m_blockchain);
544 MERROR(
"Failed to find tx in txpool");
548 auto ci = m_parsed_tx_cache.find(
id);
549 if (ci != m_parsed_tx_cache.end())
555 MERROR(
"Failed to parse tx from txpool");
571 m_txpool_weight -= tx_weight;
572 remove_transaction_keyimages(tx,
id);
575 catch (
const std::exception &e)
577 MERROR(
"Failed to remove tx from txpool: " << e.what());
581 if (sorted_it != m_txs_by_fee_and_receive_time.end())
582 m_txs_by_fee_and_receive_time.erase(sorted_it);
589 m_remove_stuck_tx_interval.
do_call([
this](){
return remove_stuck_transactions();});
592 sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(
const crypto::hash&
id)
const
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;
602 bool tx_memory_pool::remove_stuck_transactions()
606 std::list<std::pair<crypto::hash, uint64_t>> remove;
610 if((tx_age > mempool_lifetime && !meta.kept_by_block) ||
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())
617 LOG_PRINT_L1(
"Removing tx " << txid <<
" from tx pool, but it was not found in the sorted txs container!");
621 m_txs_by_fee_and_receive_time.erase(sorted_it);
623 m_timed_out_transactions.insert(txid);
624 remove.push_back(std::make_pair(txid, meta.weight));
631 LockedTXN
lock(m_blockchain);
632 for (
const std::pair<crypto::hash, uint64_t> &entry: remove)
641 MERROR(
"Failed to parse tx from txpool");
648 m_txpool_weight -= entry.second;
649 remove_transaction_keyimages(tx, txid);
652 catch (
const std::exception &e)
654 MWARNING(
"Failed to remove stuck transaction: " << txid);
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)
684 cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
685 txs.push_back(std::make_pair(txid, bd));
687 catch (const std::exception &e)
689 MERROR(
"Failed to get transaction blob from db");
703 const time_t now =
time(NULL);
704 LockedTXN
lock(m_blockchain);
705 for (
auto it = txs.begin(); it != txs.end(); ++it)
717 catch (
const std::exception &e)
719 MERROR(
"Failed to update txpool transaction metadata: " << e.what());
742 MERROR(
"Failed to parse tx from txpool");
749 },
true, include_unrelayed_txes);
760 },
false, include_unrelayed_txes);
772 },
false, include_unrelayed_txes);
780 std::map<uint64_t, txpool_histo> agebytes;
782 std::vector<uint32_t> weights;
785 weights.push_back(meta.
weight);
802 agebytes[age].bytes += meta.
weight;
808 },
false, include_unrelayed_txes);
815 std::map<uint64_t, txpool_histo>::iterator it, i2;
822 for (
size_t n=0; n <= end; n++, it--);
826 stats.
histo.resize(10);
835 delta = now - stats.
oldest;
836 stats.
histo.resize(factor);
840 for (i2 = agebytes.begin(); i2 != it; i2++)
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;
846 for (; i2 != agebytes.end(); i2++)
848 stats.
histo[factor].txs += i2->second.txs;
849 stats.
histo[factor].bytes += i2->second.bytes;
868 MERROR(
"Failed to parse tx from txpool");
893 },
true, include_sensitive_data);
896 for (
const key_images_container::value_type& kee : m_spent_key_images) {
898 const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
903 if (!include_sensitive_data)
909 MERROR(
"Failed to get tx meta from txpool");
916 catch (
const std::exception &e)
918 MERROR(
"Failed to get tx meta from txpool: " << e.what());
926 key_image_infos.push_back(ki);
942 MERROR(
"Failed to parse tx from txpool");
962 tx_infos.push_back(txi);
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;
971 tx_hashes.push_back(tx_id_hash);
975 key_image_infos[k_image] =
std::move(tx_hashes);
987 for (
const auto& image : key_images)
989 spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ?
false :
true);
1003 catch (
const std::exception &e)
1012 m_input_cache.clear();
1013 m_parsed_tx_cache.clear();
1020 m_input_cache.clear();
1021 m_parsed_tx_cache.clear();
1033 bool tx_memory_pool::key_images_already_spent(
const transaction& tx)
const
1037 for(
const auto& in: tx.
vin)
1041 const auto &tokey_in = boost::get<txin_to_key>(in);
1042 if(have_tx_keyimg_as_spent(tokey_in.k_image))
1049 bool tx_memory_pool::utxo_nonexistent(
const transaction& tx)
const
1053 for(
const auto& in: tx.vin)
1055 if (
in.type() ==
typeid(txin_to_key_public))
1057 const auto &tokey_in = boost::get<txin_to_key_public>(in);
1058 if(have_tx_utxo_as_spent(tokey_in))
1065 bool tx_memory_pool::have_tx_keyimg_as_spent(
const crypto::key_image& key_im)
const
1068 return m_spent_key_images.end() != m_spent_key_images.find(key_im);
1071 bool tx_memory_pool::have_tx_utxo_as_spent(
const txin_to_key_public& in)
const
1075 return m_spent_utxos.end() != m_spent_utxos.find(txin_key);
1080 m_transactions_lock.
lock();
1085 m_transactions_lock.
unlock();
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())
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);
1101 bool ret = m_blockchain.
check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, 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)));
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
1109 struct transction_parser
1117 throw std::runtime_error(
"failed to parse transaction blob");
1127 } lazy_tx(txblob, txid, tx);
1131 if(txd.max_used_block_id == null_hash)
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))
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))
1167 txd.double_spend_seen =
true;
1172 txd.utxo_nonexistent_seen =
true;
1180 bool tx_memory_pool::have_key_images(
const std::unordered_set<crypto::key_image>& k_images,
const transaction_prefix& tx)
1182 for(
size_t i = 0; i!= tx.vin.size(); i++)
1184 if(tx.vin[i].type() ==
typeid(txin_to_key))
1186 const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1187 if(k_images.count(itk.k_image))
1194 bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images,
const transaction_prefix& tx)
1196 for(
size_t i = 0; i!= tx.vin.size(); i++)
1198 if(tx.vin[i].type() ==
typeid(txin_to_key))
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);
1208 bool tx_memory_pool::have_utxos(
const std::unordered_set<std::string>& utxos,
const transaction_prefix& tx)
1210 for(
size_t i = 0; i!= tx.vin.size(); i++)
1212 if(tx.vin[i].type() ==
typeid(txin_to_key_public))
1214 const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1216 if(utxos.count(txin_key))
1224 bool tx_memory_pool::append_utxos(std::unordered_set<std::string>& utxos,
const transaction_prefix& tx)
1226 for(
size_t i = 0; i!= tx.vin.size(); i++)
1228 if(tx.vin[i].type() ==
typeid(txin_to_key_public))
1230 const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
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);
1240 void tx_memory_pool::mark_double_spend_or_nonexistent_utxo(
const transaction &tx)
1244 bool changed =
false;
1245 LockedTXN
lock(m_blockchain);
1246 for(
size_t i = 0; i!= tx.vin.size(); i++)
1248 if(tx.vin[i].type() ==
typeid(txin_to_key))
1251 const key_images_container::const_iterator it = m_spent_key_images.find(itk.k_image);
1252 if (it != m_spent_key_images.end())
1256 txpool_tx_meta_t meta;
1259 MERROR(
"Failed to find tx meta in txpool");
1263 if (!meta.double_spend_seen)
1265 MDEBUG(
"Marking " << txid <<
" as double spending " << itk.k_image);
1266 meta.double_spend_seen =
true;
1272 catch (
const std::exception &e)
1274 MERROR(
"Failed to update tx meta: " << e.what());
1281 else if (tx.vin[i].type() ==
typeid(txin_to_key_public))
1285 const utxos_container::const_iterator it = m_spent_utxos.find(txin_key);
1286 if (it != m_spent_utxos.end())
1290 txpool_tx_meta_t meta;
1293 MERROR(
"Failed to find tx meta in txpool");
1297 if (!meta.double_spend_seen)
1299 MDEBUG(
"Marking " << txid <<
" as double spending " << txin_key);
1300 meta.utxo_nonexistent_seen =
true;
1306 catch (
const std::exception &e)
1308 MERROR(
"Failed to update tx meta: " << e.what());
1327 std::stringstream ss;
1331 ss <<
"id: " << txid << std::endl;
1332 if (!short_format) {
1336 MERROR(
"Failed to parse tx from txpool");
1341 ss <<
"blob_size: " << (short_format ?
"-" :
std::to_string(txblob->size())) << std::endl
1342 <<
"weight: " << meta.
weight << std::endl
1344 <<
"kept_by_block: " << (meta.
kept_by_block ?
'T' :
'F') << std::endl
1363 uint64_t best_coinbase = 0, coinbase = 0;
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;
1377 LOG_PRINT_L2(
"Filling block template, median weight " << median_weight <<
", " << m_txs_by_fee_and_receive_time.size() <<
" txes in the pool");
1379 LockedTXN
lock(m_blockchain);
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)
1387 MERROR(
" failed to find tx meta");
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));
1393 if (max_total_weight < total_weight + meta.
weight)
1410 coinbase = block_reward + fee + meta.
fee;
1411 if (coinbase < template_accept_threshold(best_coinbase))
1421 if (total_weight > median_weight)
1438 ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
1440 catch (
const std::exception &e)
1442 MERROR(
"Failed to check transaction readiness: " << e.what());
1445 if (memcmp(&original_meta, &meta,
sizeof(meta)))
1451 catch (
const std::exception &e)
1453 MERROR(
"Failed to update tx meta: " << e.what());
1462 if (have_key_images(k_images, tx))
1467 if (have_utxos(utxos, tx))
1473 bl.
tx_hashes.push_back(sorted_it->second);
1474 total_weight += meta.
weight;
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));
1483 expected_reward = best_coinbase;
1485 << total_weight <<
"/" << max_total_weight <<
", coinbase " <<
print_etn(best_coinbase)
1486 <<
" (including " <<
print_etn(fee) <<
" in fees)");
1494 size_t tx_weight_limit = get_transaction_weight_limit(
version);
1495 std::unordered_set<crypto::hash> remove;
1497 m_txpool_weight = 0;
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);
1505 LOG_PRINT_L1(
"Transaction " << txid <<
" is in the blockchain, removing it from pool");
1506 remove.insert(txid);
1511 size_t n_removed = 0;
1512 if (!remove.empty())
1514 LockedTXN
lock(m_blockchain);
1523 MERROR(
"Failed to parse tx from txpool");
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())
1533 LOG_PRINT_L1(
"Removing tx " << txid <<
" from tx pool, but it was not found in the sorted txs container!");
1537 m_txs_by_fee_and_receive_time.erase(sorted_it);
1541 catch (
const std::exception &e)
1543 MERROR(
"Failed to remove invalid tx from pool");
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;
1568 for (
int pass = 0; pass < 2; ++pass)
1570 const bool kept = pass == 1;
1577 MWARNING(
"Failed to parse tx from txpool, removing");
1578 remove.push_back(txid);
1581 if (tx.version <= 2 && !insert_key_images(tx, txid, meta.
kept_by_block))
1583 MFATAL(
"Failed to insert key images from txpool tx");
1586 if (tx.version >= 3 && !insert_utxos(tx, txid, meta.
kept_by_block))
1588 MFATAL(
"Failed to insert utxos from txpool tx");
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;
1598 if (!remove.empty())
1600 LockedTXN
lock(m_blockchain);
1601 for (
const auto &txid: remove)
1607 catch (
const std::exception &e)
1609 MWARNING(
"Failed to remove corrupt transaction: " << txid);
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
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
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
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
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
std::vector< txin_v > vin
void set_hash(const crypto::hash &h)
void unlock() const
unlocks the transaction pool
void lock() const
locks the transaction pool
void on_idle()
action to take periodically
void set_relayed(const std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs)
tell the pool that certain transactions were just relayed
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
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
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.
bool have_tx(const crypto::hash &id) const
checks if the pool has a transaction with the given hash
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
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
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)
void set_txpool_max_weight(size_t bytes)
set the max cumulative txpool weight in bytes
void get_transactions(std::vector< transaction > &txs, bool include_unrelayed_txes=true) const
get a list of all transactions in the pool
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
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
bool init(size_t max_txpool_weight=0)
loads pool state (if any) from disk, and initializes pool
std::string print_pool(bool short_format) const
get a string containing human-readable pool information
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
size_t validate(uint8_t version)
remove transactions from the pool which are no longer valid
size_t get_txpool_weight() const
get the cumulative txpool weight in bytes
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
size_t get_transactions_count(bool include_unrelayed_txes=true) const
get the total number of transactions in the pool
bool get_relayable_transactions(std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs) const
get a list of all relayable transactions and their hashes
bool get_transaction(const crypto::hash &h, cryptonote::blobdata &txblob) const
get a specific transaction from the pool
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
bool deinit()
attempts to save the transaction pool state to disk
bool do_call(functor_t functr)
#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 CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
std::unordered_map< crypto::key_image, std::vector< crypto::hash > > key_images_with_tx_hashes
Holds cryptonote related classes and helpers.
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)
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)
version
Supported socks variants.
key commit(etn_amount amount, const key &mask)
const T & move(const T &t)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
unsigned __int64 uint64_t
std::vector< crypto::hash > tx_hashes
crypto::hash last_failed_block_hash
cryptonote::transaction tx
uint64_t last_relayed_time
bool nonexistent_utxo_seen
uint64_t last_failed_block_height
uint64_t max_used_block_height
crypto::hash max_used_block_hash
std::vector< std::string > txs_hashes
std::string max_used_block_id_hash
uint64_t max_used_block_height
uint64_t last_failed_height
bool nonexistent_utxo_seen
std::string last_failed_id_hash
uint64_t last_relayed_time
bool m_verification_failed
bool m_verification_impossible
uint32_t num_double_spends
std::vector< txpool_histo > histo
uint32_t num_nonexistent_utxos
#define CRITICAL_REGION_LOCAL1(x)
#define CRITICAL_REGION_LOCAL(x)
DISABLE_VS_WARNINGS(4244 4345 4503) using namespace crypto