33 #include <boost/filesystem.hpp> 34 #include <unordered_set> 53 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 54 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "txpool" 69 time_t
const MIN_RELAY_TIME = (60 * 5);
70 time_t
const MAX_RELAY_TIME = (60 * 60 * 4);
71 float const ACCEPT_THRESHOLD = 1.0f;
74 uint64_t get_relay_delay(time_t now, time_t received)
76 time_t d = (now - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME;
77 if (d > MAX_RELAY_TIME)
84 return amount * ACCEPT_THRESHOLD;
102 LockedTXN(Blockchain &b): m_blockchain(b), m_batch(
false), m_active(
false) {
103 m_batch = m_blockchain.get_db().batch_start();
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(); }
110 Blockchain &m_blockchain;
138 if (!kept_by_block && m_timed_out_transactions.find(
id) != m_timed_out_transactions.end())
171 fee = inputs_amount - outputs_amount;
174 if(outputs_amount != inputs_amount)
176 LOG_PRINT_L1(
"transaction fee isnt zero: outputs_amount != inputs_amount, rejecting.");
182 LOG_PRINT_L1(
"We are migrating to aurelius and this transaction should have zero fee and it doesn't, rejecting.");
188 if(outputs_amount > inputs_amount)
195 else if(tx.
version != 2 && outputs_amount == inputs_amount)
200 LOG_PRINT_L1(
"v1 transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
214 portal_address_viewkey_hex_str =
"2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
215 portal_address_spendkey_hex_str =
"8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
217 portal_address_viewkey_hex_str =
"5866666666666666666666666666666666666666666666666666666666666666";
218 portal_address_spendkey_hex_str =
"5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3";
220 bool is_sc_migration =
true;
221 for (
auto output: tx.
vout){
222 const auto out = boost::get<txout_to_key_public>(output.target);
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= " 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= " 248 if(tx.
version == 2 && fee != 0)
250 LOG_PRINT_L1(
"transaction v2 fee is greater than zero, rejecting.");
255 if (tx.
version != 2 && !kept_by_block && !m_blockchain.
check_fee(tx_weight, fee))
263 size_t tx_weight_limit = get_transaction_weight_limit(
version);
266 LOG_PRINT_L1(
"transaction is too heavy: " << tx_weight <<
" bytes, maximum weight: " << tx_weight_limit);
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");
287 if (utxo_nonexistent(tx)) {
288 mark_double_spend_or_nonexistent_utxo(tx);
289 LOG_PRINT_L1(
"Transaction with id= " <<
id <<
" used nonexistent utxos");
299 LOG_PRINT_L1(
"Transaction with id= "<<
id <<
" has at least one invalid output");
308 time_t receive_time =
time(
nullptr);
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);
326 std::vector<tx_extra_field> tx_extra_fields;
336 tvc.m_verification_failed =
true;
337 tvc.m_bad_bridge_source_address =
true;
341 bool valid_smartchain_address =
true;
342 std::string string_smartchain_address = bridge_smartchain_address.
data;
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;
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);
355 if(isMixedCase && valid_smartchain_address !=
false){
357 std::string lower_address = string_smartchain_address.substr(2);
358 std::transform(lower_address.begin(), lower_address.end(), lower_address.begin(), ::tolower);
360 unsigned char hashed_lower[32];
361 keccak(reinterpret_cast<const uint8_t *>(lower_address.data()), 40, hashed_lower, 32);
365 for (
size_t i = 0; i < lower_address.length(); i++) {
367 hash += lower_address[i];
369 else if (address_hash[i] >=
'8') {
370 hash += std::toupper(lower_address[i]);
373 hash += lower_address[i];
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;
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;
387 else if (checksum[i - 2] != string_smartchain_address[i]) {
388 valid_smartchain_address =
false;
394 if(!valid_smartchain_address){
395 tvc.m_verification_failed =
true;
396 tvc.m_bad_bridge_smartchain_address =
true;
403 portal_address_viewkey_hex_str =
"2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
404 portal_address_spendkey_hex_str =
"8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
406 portal_address_viewkey_hex_str =
"5866666666666666666666666666666666666666666666666666666666666666";
407 portal_address_spendkey_hex_str =
"5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3";
410 for (
auto output: tx.
vout){
411 const auto out = boost::get<txout_to_key_public>(output.target);
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;
446 m_parsed_tx_cache.insert(std::make_pair(
id, tx));
448 LockedTXN
lock(m_blockchain);
450 if ((tx.
version <= 2 && !insert_key_images(tx,
id, kept_by_block)) || (tx.
version >= 3 && !insert_utxos(tx,
id, kept_by_block)))
452 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (
double)tx_weight, receive_time),
id);
455 catch (
const std::exception &e)
457 MERROR(
"transaction already exists at inserting in memory pool: " << e.what());
460 tvc.m_verification_impossible =
true;
461 tvc.m_added_to_pool =
true;
465 tvc.m_verification_failed =
true;
466 tvc.m_invalid_input =
true;
491 m_parsed_tx_cache.insert(std::make_pair(
id, tx));
493 LockedTXN
lock(m_blockchain);
496 if ((tx.
version <= 2 && !insert_key_images(tx,
id, kept_by_block)) || (tx.
version >= 3 && !insert_utxos(tx,
id, kept_by_block)))
498 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (
double)tx_weight, receive_time),
id);
501 catch (
const std::exception &e)
503 MERROR(
"internal error: transaction already exists at inserting in memory pool: " << e.what());
506 tvc.m_added_to_pool =
true;
509 tvc.m_should_be_relayed =
true;
512 tvc.m_verification_failed =
false;
513 m_txpool_weight += tx_weight;
517 MINFO(
"Transaction added to pool: txid " <<
id <<
" weight: " << tx_weight <<
" fee/byte: " << (fee / (
double)tx_weight));
519 prune(m_txpool_max_weight);
527 size_t blob_size = 0;
538 return m_txpool_weight;
544 m_txpool_max_weight = bytes;
547 void tx_memory_pool::prune(
size_t bytes)
551 bytes = m_txpool_max_weight;
553 LockedTXN
lock(m_blockchain);
554 bool changed =
false;
557 auto it = --m_txs_by_fee_and_receive_time.end();
558 while (it != m_txs_by_fee_and_receive_time.begin())
560 if (m_txpool_weight <= bytes)
568 MERROR(
"Failed to find tx in txpool");
581 MERROR(
"Failed to parse tx from txpool");
585 MINFO(
"Pruning tx " << txid <<
" from txpool: weight: " << meta.
weight <<
", fee/byte: " << it->first.first);
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--);
593 catch (
const std::exception &e)
595 MERROR(
"Error while pruning txpool: " << e.what());
602 if (m_txpool_weight > bytes)
603 MINFO(
"Pool weight after pruning is larger than limit: " << m_txpool_weight <<
"/" << bytes);
606 bool tx_memory_pool::insert_key_images(
const transaction_prefix &tx,
const crypto::hash &
id,
bool kept_by_block)
608 for(
const auto& in: tx.vin)
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 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");
622 bool tx_memory_pool::insert_utxos(
const transaction_prefix &tx,
const crypto::hash &
id,
bool kept_by_block)
624 for(
const auto& in: tx.vin)
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 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");
642 bool tx_memory_pool::remove_transaction_keyimages(
const transaction_prefix& tx,
const crypto::hash &actual_hash)
647 for(
const txin_v& vi: tx.vin)
649 if(vi.type() ==
typeid(txin_to_key))
651 const auto &txin = boost::get<txin_to_key>(vi);
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;
658 <<
"transaction id = " << actual_hash);
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())
667 m_spent_key_images.erase(it);
670 else if (vi.type() ==
typeid(txin_to_key_public))
672 const auto &txin = boost::get<txin_to_key_public>(vi);
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;
681 <<
"transaction id = " << actual_hash);
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);
690 m_spent_utxos.erase(it);
707 auto sorted_it = find_tx_in_sorted_container(
id);
711 LockedTXN
lock(m_blockchain);
715 MERROR(
"Failed to find tx in txpool");
719 auto ci = m_parsed_tx_cache.find(
id);
720 if (ci != m_parsed_tx_cache.end())
726 MERROR(
"Failed to parse tx from txpool");
742 m_txpool_weight -= tx_weight;
743 remove_transaction_keyimages(tx,
id);
746 catch (
const std::exception &e)
748 MERROR(
"Failed to remove tx from txpool: " << e.what());
752 if (sorted_it != m_txs_by_fee_and_receive_time.end())
753 m_txs_by_fee_and_receive_time.erase(sorted_it);
760 m_remove_stuck_tx_interval.
do_call([
this](){
return remove_stuck_transactions();});
763 sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(
const crypto::hash&
id)
const 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;
773 bool tx_memory_pool::remove_stuck_transactions()
777 std::list<std::pair<crypto::hash, uint64_t>>
remove;
781 if((tx_age > mempool_lifetime && !meta.kept_by_block) ||
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())
788 LOG_PRINT_L1(
"Removing tx " << txid <<
" from tx pool, but it was not found in the sorted txs container!");
792 m_txs_by_fee_and_receive_time.erase(sorted_it);
794 m_timed_out_transactions.insert(txid);
795 remove.push_back(std::make_pair(txid, meta.weight));
802 LockedTXN
lock(m_blockchain);
803 for (
const std::pair<crypto::hash, uint64_t> &entry:
remove)
812 MERROR(
"Failed to parse tx from txpool");
819 m_txpool_weight -= entry.second;
820 remove_transaction_keyimages(tx, txid);
823 catch (
const std::exception &e)
825 MWARNING(
"Failed to remove stuck transaction: " << txid);
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)
855 cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
856 txs.push_back(std::make_pair(txid, bd));
858 catch (const std::exception &e)
860 MERROR(
"Failed to get transaction blob from db");
874 const time_t now =
time(NULL);
875 LockedTXN
lock(m_blockchain);
876 for (
auto it = txs.begin(); it != txs.end(); ++it)
888 catch (
const std::exception &e)
890 MERROR(
"Failed to update txpool transaction metadata: " << e.what());
913 MERROR(
"Failed to parse tx from txpool");
920 },
true, include_unrelayed_txes);
931 },
false, include_unrelayed_txes);
943 },
false, include_unrelayed_txes);
951 std::map<uint64_t, txpool_histo> agebytes;
953 std::vector<uint32_t> weights;
956 weights.push_back(meta.
weight);
973 agebytes[age].bytes += meta.
weight;
979 },
false, include_unrelayed_txes);
986 std::map<uint64_t, txpool_histo>::iterator it, i2;
993 for (
size_t n=0; n <= end; n++, it--);
997 stats.
histo.resize(10);
1004 it = agebytes.end();
1006 delta = now - stats.
oldest;
1007 stats.
histo.resize(factor);
1011 for (i2 = agebytes.begin(); i2 != it; i2++)
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;
1017 for (; i2 != agebytes.end(); i2++)
1019 stats.
histo[factor].txs += i2->second.txs;
1020 stats.
histo[factor].bytes += i2->second.bytes;
1039 MERROR(
"Failed to parse tx from txpool");
1064 },
true, include_sensitive_data);
1067 for (
const key_images_container::value_type& kee : m_spent_key_images) {
1069 const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
1074 if (!include_sensitive_data)
1080 MERROR(
"Failed to get tx meta from txpool");
1087 catch (
const std::exception &e)
1089 MERROR(
"Failed to get tx meta from txpool: " << e.what());
1097 key_image_infos.push_back(ki);
1113 MERROR(
"Failed to parse tx from txpool");
1133 tx_infos.push_back(txi);
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;
1142 tx_hashes.push_back(tx_id_hash);
1146 key_image_infos[k_image] =
std::move(tx_hashes);
1158 for (
const auto& image : key_images)
1160 spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ?
false :
true);
1174 catch (
const std::exception &e)
1183 m_input_cache.clear();
1184 m_parsed_tx_cache.clear();
1191 m_input_cache.clear();
1192 m_parsed_tx_cache.clear();
1204 bool tx_memory_pool::key_images_already_spent(
const transaction& tx)
const 1208 for(
const auto& in: tx.
vin)
1212 const auto &tokey_in = boost::get<txin_to_key>(in);
1213 if(have_tx_keyimg_as_spent(tokey_in.k_image))
1223 return have_tx_utxo_as_spent(in);
1226 bool tx_memory_pool::utxo_nonexistent(
const transaction& tx)
const 1230 for(
const auto& in: tx.
vin)
1234 const auto &tokey_in = boost::get<txin_to_key_public>(in);
1235 if(have_tx_utxo_as_spent(tokey_in))
1242 bool tx_memory_pool::have_tx_keyimg_as_spent(
const crypto::key_image& key_im)
const 1245 return m_spent_key_images.end() != m_spent_key_images.find(key_im);
1248 bool tx_memory_pool::have_tx_utxo_as_spent(
const txin_to_key_public& in)
const 1252 return m_spent_utxos.end() != m_spent_utxos.find(txin_key);
1257 m_transactions_lock.
lock();
1262 m_transactions_lock.
unlock();
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())
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);
1278 bool ret = m_blockchain.
check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, 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)));
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 1286 struct transction_parser
1294 throw std::runtime_error(
"failed to parse transaction blob");
1304 } lazy_tx(txblob, txid, tx);
1308 if(txd.max_used_block_id == null_hash)
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))
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))
1344 txd.double_spend_seen =
true;
1349 txd.utxo_nonexistent_seen =
true;
1357 bool tx_memory_pool::have_key_images(
const std::unordered_set<crypto::key_image>& k_images,
const transaction_prefix& tx)
1359 for(
size_t i = 0; i!= tx.vin.size(); i++)
1361 if(tx.vin[i].type() ==
typeid(txin_to_key))
1363 const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1364 if(k_images.count(itk.k_image))
1371 bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images,
const transaction_prefix& tx)
1373 for(
size_t i = 0; i!= tx.vin.size(); i++)
1375 if(tx.vin[i].type() ==
typeid(txin_to_key))
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);
1385 bool tx_memory_pool::have_utxos(
const std::unordered_set<std::string>& utxos,
const transaction_prefix& tx)
1387 for(
size_t i = 0; i!= tx.vin.size(); i++)
1389 if(tx.vin[i].type() ==
typeid(txin_to_key_public))
1391 const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1393 if(utxos.count(txin_key))
1401 bool tx_memory_pool::append_utxos(std::unordered_set<std::string>& utxos,
const transaction_prefix& tx)
1403 for(
size_t i = 0; i!= tx.vin.size(); i++)
1405 if(tx.vin[i].type() ==
typeid(txin_to_key_public))
1407 const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
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);
1417 void tx_memory_pool::mark_double_spend_or_nonexistent_utxo(
const transaction &tx)
1421 bool changed =
false;
1422 LockedTXN
lock(m_blockchain);
1423 for(
size_t i = 0; i!= tx.vin.size(); i++)
1425 if(tx.vin[i].type() ==
typeid(txin_to_key))
1428 const key_images_container::const_iterator it = m_spent_key_images.find(itk.k_image);
1429 if (it != m_spent_key_images.end())
1433 txpool_tx_meta_t meta;
1436 MERROR(
"Failed to find tx meta in txpool");
1440 if (!meta.double_spend_seen)
1442 MDEBUG(
"Marking " << txid <<
" as double spending " << itk.k_image);
1443 meta.double_spend_seen =
true;
1449 catch (
const std::exception &e)
1451 MERROR(
"Failed to update tx meta: " << e.what());
1458 else if (tx.vin[i].type() ==
typeid(txin_to_key_public))
1462 const utxos_container::const_iterator it = m_spent_utxos.find(txin_key);
1463 if (it != m_spent_utxos.end())
1467 txpool_tx_meta_t meta;
1470 MERROR(
"Failed to find tx meta in txpool");
1474 if (!meta.double_spend_seen)
1476 MDEBUG(
"Marking " << txid <<
" as double spending " << txin_key);
1477 meta.utxo_nonexistent_seen =
true;
1483 catch (
const std::exception &e)
1485 MERROR(
"Failed to update tx meta: " << e.what());
1504 std::stringstream ss;
1508 ss <<
"id: " << txid << std::endl;
1509 if (!short_format) {
1513 MERROR(
"Failed to parse tx from txpool");
1518 ss <<
"blob_size: " << (short_format ?
"-" :
std::to_string(txblob->size())) << std::endl
1519 <<
"weight: " << meta.
weight << std::endl
1521 <<
"kept_by_block: " << (meta.
kept_by_block ?
'T' :
'F') << std::endl
1540 uint64_t best_coinbase = 0, coinbase = 0;
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;
1554 LOG_PRINT_L2(
"Filling block template, median weight " << median_weight <<
", " << m_txs_by_fee_and_receive_time.size() <<
" txes in the pool");
1556 LockedTXN
lock(m_blockchain);
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)
1564 MERROR(
" failed to find tx meta");
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));
1570 if (max_total_weight < total_weight + meta.
weight)
1587 coinbase = block_reward + fee + meta.
fee;
1588 if (coinbase < template_accept_threshold(best_coinbase))
1598 if (total_weight > median_weight)
1615 ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
1617 catch (
const std::exception &e)
1619 MERROR(
"Failed to check transaction readiness: " << e.what());
1622 if (memcmp(&original_meta, &meta,
sizeof(meta)))
1628 catch (
const std::exception &e)
1630 MERROR(
"Failed to update tx meta: " << e.what());
1639 if (have_key_images(k_images, tx))
1644 if (have_utxos(utxos, tx))
1650 bl.
tx_hashes.push_back(sorted_it->second);
1651 total_weight += meta.
weight;
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));
1660 expected_reward = best_coinbase;
1662 << total_weight <<
"/" << max_total_weight <<
", coinbase " <<
print_etn(best_coinbase)
1663 <<
" (including " <<
print_etn(fee) <<
" in fees)");
1671 size_t tx_weight_limit = get_transaction_weight_limit(
version);
1672 std::unordered_set<crypto::hash>
remove;
1674 m_txpool_weight = 0;
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);
1682 LOG_PRINT_L1(
"Transaction " << txid <<
" is in the blockchain, removing it from pool");
1683 remove.insert(txid);
1688 size_t n_removed = 0;
1689 if (!
remove.
empty())
1691 LockedTXN
lock(m_blockchain);
1700 MERROR(
"Failed to parse tx from txpool");
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())
1710 LOG_PRINT_L1(
"Removing tx " << txid <<
" from tx pool, but it was not found in the sorted txs container!");
1714 m_txs_by_fee_and_receive_time.erase(sorted_it);
1718 catch (
const std::exception &e)
1720 MERROR(
"Failed to remove invalid tx from pool");
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;
1745 for (
int pass = 0; pass < 2; ++pass)
1747 const bool kept = pass == 1;
1754 MWARNING(
"Failed to parse tx from txpool, removing");
1755 remove.push_back(txid);
1758 if (tx.version <= 2 && !insert_key_images(tx, txid, meta.
kept_by_block))
1760 MFATAL(
"Failed to insert key images from txpool tx");
1763 if (tx.version >= 3 && !insert_utxos(tx, txid, meta.
kept_by_block))
1765 MFATAL(
"Failed to insert utxos from txpool tx");
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;
1775 if (!
remove.
empty())
1777 LockedTXN
lock(m_blockchain);
1778 for (
const auto &txid:
remove)
1784 catch (
const std::exception &e)
1786 MWARNING(
"Failed to remove corrupt transaction: " << txid);
void on_idle()
action to take periodically
#define CRITICAL_REGION_LOCAL1(x)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
crypto::hash max_used_block_hash
std::vector< crypto::hash > tx_hashes
uint32_t num_double_spends
bool add_tx(transaction &tx, const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context &tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
bool check_outs_valid(const transaction &tx)
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
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
bool m_verification_failed
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
key commit(etn_amount amount, const key &mask)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
size_t get_txpool_weight() const
get the cumulative txpool weight in bytes
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
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)
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
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)
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
cryptonote::transaction tx
std::unordered_map< crypto::key_image, std::vector< crypto::hash > > key_images_with_tx_hashes
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE
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
std::vector< uint8_t > extra
uint64_t max_used_block_height
uint64_t last_failed_height
uint64_t max_used_block_height
std::vector< tx_out > vout
bool init(size_t max_txpool_weight=0)
loads pool state (if any) from disk, and initializes pool
Holds cryptonote related classes and helpers.
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
std::vector< txin_v > vin
std::vector< txpool_histo > histo
size_t validate(uint8_t version)
remove transactions from the pool which are no longer valid
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
uint64_t get_txpool_tx_count(bool include_unrelayed_txes=true) const
bool check_inputs_types_supported(const transaction &tx)
uint64_t last_failed_block_height
std::vector< std::string > txs_hashes
std::string obj_to_json_str(T &obj)
unsigned __int64 uint64_t
#define CRITICAL_REGION_LOCAL(x)
void set_relayed(const std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs)
tell the pool that certain transactions were just relayed
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
uint32_t num_nonexistent_utxos
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
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
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool nonexistent_utxo_seen
version
Supported socks variants.
std::string max_used_block_id_hash
const BlockchainDB & get_db() const
get a reference to the BlockchainDB in use by Blockchain
bool check_fee(size_t tx_weight, uint64_t fee) const
validate a transaction's fee
uint64_t last_relayed_time
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
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
type_vec_type median(std::vector< type_vec_type > &v)
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block's hash given a height
uint32_t get_mempool_tx_livetime() const
void unlock() const
unlocks the transaction pool
bool deinit()
attempts to save the transaction pool state to disk
const T & move(const T &t)
bool have_tx(const crypto::hash &id) const
search the blockchain for a transaction by hash
bool get_transaction(const crypto::hash &h, cryptonote::blobdata &txblob) const
get a specific transaction from the pool
crypto::hash last_failed_block_hash
void set_txpool_max_weight(size_t bytes)
set the max cumulative txpool weight in bytes
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
bool nonexistent_utxo_seen
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.
network_type get_nettype() const
get blockchain nettype
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
DISABLE_VS_WARNINGS(4244 4345 4503) using namespace crypto
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 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)
bool check_tx_outputs(const transaction &tx, tx_verification_context &tvc)
check that a transaction's outputs conform to current standards
void lock() const
locks the transaction pool
#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
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)
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
std::string last_failed_id_hash
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
uint64_t last_relayed_time
std::string print_pool(bool short_format) const
get a string containing human-readable pool information
bool get_relayable_transactions(std::vector< std::pair< crypto::hash, cryptonote::blobdata >> &txs) const
get a list of all relayable transactions and their hashes