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;
173 if(tx.
version == 3 && m_blockchain.get_current_blockchain_height() > (m_blockchain.get_nettype() ==
MAINNET ? 1811310 : 1455270)) {
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.");
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";
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");
297 if (!m_blockchain.check_tx_outputs(tx, tvc))
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);
316 if(tx.
version == 3 && m_blockchain.get_current_blockchain_height() > (m_blockchain.get_nettype() ==
MAINNET ? 1811310 : 1455270)) {
326 std::vector<tx_extra_field> tx_extra_fields;
348 std::string sig_message = bridge_source_address.
data + bridge_smartchain_address.
data;
360 bool valid_smartchain_address =
true;
361 std::string string_smartchain_address = bridge_smartchain_address.
data;
363 std::regex pattern(
"^(0x|0X)[a-fA-F0-9]{40}$");
364 if(!std::regex_match(string_smartchain_address, pattern))
365 valid_smartchain_address =
false;
368 bool isMixedCase = std::any_of(string_smartchain_address.begin(), string_smartchain_address.end(), [](
char c) {
369 return std::isupper(c);
370 }) && std::any_of(string_smartchain_address.begin(), string_smartchain_address.end(), [](
char c) {
371 return std::islower(c);
374 if(isMixedCase && valid_smartchain_address !=
false){
376 std::string lower_address = string_smartchain_address.substr(2);
377 std::transform(lower_address.begin(), lower_address.end(), lower_address.begin(), ::tolower);
379 unsigned char hashed_lower[32];
380 keccak(
reinterpret_cast<const uint8_t *
>(lower_address.data()), 40, hashed_lower, 32);
384 for (
size_t i = 0; i < lower_address.length(); i++) {
385 if (std::isdigit(lower_address[i])) {
386 hash += lower_address[i];
388 else if (address_hash[i] >=
'8') {
389 hash += std::toupper(lower_address[i]);
392 hash += lower_address[i];
395 std::string checksum =
hash.substr(0, 8);
396 for (
size_t i = 2; i < checksum.length() + 2; i++) {
397 if (std::islower(string_smartchain_address[i]) && checksum[i - 2] <
'a') {
398 valid_smartchain_address =
false;
400 else if (std::isupper(string_smartchain_address[i]) && checksum[i - 2] <
'A') {
401 char lower_char = std::tolower(string_smartchain_address[i]);
402 if (checksum[i - 2] != lower_char) {
403 valid_smartchain_address =
false;
406 else if (checksum[i - 2] != string_smartchain_address[i]) {
407 valid_smartchain_address =
false;
413 if(!valid_smartchain_address){
419 std::string portal_address_viewkey_hex_str;
420 std::string portal_address_spendkey_hex_str;
421 if(m_blockchain.get_nettype() ==
MAINNET){
422 portal_address_viewkey_hex_str =
"2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
423 portal_address_spendkey_hex_str =
"8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
425 portal_address_viewkey_hex_str =
"5866666666666666666666666666666666666666666666666666666666666666";
426 portal_address_spendkey_hex_str =
"5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3";
429 for (
auto output: tx.
vout){
430 const auto out = boost::get<txout_to_key_public>(output.target);
433 if(out_spendkey_str != portal_address_spendkey_hex_str || out_viewkey_str != portal_address_viewkey_hex_str){
465 m_parsed_tx_cache.insert(std::make_pair(
id, tx));
467 LockedTXN
lock(m_blockchain);
468 m_blockchain.add_txpool_tx(
id, blob, meta);
469 if ((tx.
version <= 2 && !insert_key_images(tx,
id, kept_by_block)) || (tx.
version >= 3 && !insert_utxos(tx,
id, kept_by_block)))
471 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (
double)tx_weight, receive_time),
id);
474 catch (
const std::exception &e)
476 MERROR(
"transaction already exists at inserting in memory pool: " << e.what());
510 m_parsed_tx_cache.insert(std::make_pair(
id, tx));
512 LockedTXN
lock(m_blockchain);
513 m_blockchain.remove_txpool_tx(
id);
514 m_blockchain.add_txpool_tx(
id, blob, meta);
515 if ((tx.
version <= 2 && !insert_key_images(tx,
id, kept_by_block)) || (tx.
version >= 3 && !insert_utxos(tx,
id, kept_by_block)))
517 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (
double)tx_weight, receive_time),
id);
520 catch (
const std::exception &e)
522 MERROR(
"internal error: transaction already exists at inserting in memory pool: " << e.what());
532 m_txpool_weight += tx_weight;
536 MINFO(
"Transaction added to pool: txid " <<
id <<
" weight: " << tx_weight <<
" fee/byte: " << (fee / (
double)tx_weight));
538 prune(m_txpool_max_weight);
546 size_t blob_size = 0;
557 return m_txpool_weight;
563 m_txpool_max_weight = bytes;
566 void tx_memory_pool::prune(
size_t bytes)
570 bytes = m_txpool_max_weight;
572 LockedTXN
lock(m_blockchain);
573 bool changed =
false;
576 auto it = --m_txs_by_fee_and_receive_time.end();
577 while (it != m_txs_by_fee_and_receive_time.begin())
579 if (m_txpool_weight <= bytes)
587 MERROR(
"Failed to find tx in txpool");
597 cryptonote::transaction_prefix tx;
600 MERROR(
"Failed to parse tx from txpool");
604 MINFO(
"Pruning tx " << txid <<
" from txpool: weight: " << meta.
weight <<
", fee/byte: " << it->first.first);
605 m_blockchain.remove_txpool_tx(txid);
606 m_txpool_weight -= meta.
weight;
607 remove_transaction_keyimages(tx, txid);
608 MINFO(
"Pruned tx " << txid <<
" from txpool: weight: " << meta.
weight <<
", fee/byte: " << it->first.first);
609 m_txs_by_fee_and_receive_time.erase(it--);
612 catch (
const std::exception &e)
614 MERROR(
"Error while pruning txpool: " << e.what());
621 if (m_txpool_weight > bytes)
622 MINFO(
"Pool weight after pruning is larger than limit: " << m_txpool_weight <<
"/" << bytes);
627 for(
const auto& in: tx.vin)
630 std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
631 CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0,
false,
"internal error: kept_by_block=" << kept_by_block
632 <<
", kei_image_set.size()=" << kei_image_set.size() <<
ENDL <<
"txin.k_image=" << txin.k_image <<
ENDL
634 auto ins_res = kei_image_set.insert(
id);
635 CHECK_AND_ASSERT_MES(ins_res.second,
false,
"internal error: try to insert duplicate iterator in key_image set");
643 for(
const auto& in: tx.vin)
647 std::unordered_set<crypto::hash>& utxo_set = m_spent_utxos[txin_key];
648 CHECK_AND_ASSERT_MES(kept_by_block || utxo_set.size() == 0,
false,
"internal error: kept_by_block=" << kept_by_block
649 <<
", utxo_set.size()=" << utxo_set.size() <<
ENDL <<
"txin=" << txin_key <<
ENDL
651 auto ins_res = utxo_set.insert(
id);
652 CHECK_AND_ASSERT_MES(ins_res.second,
false,
"internal error: try to insert duplicate iterator in utxo set");
666 for(
const txin_v& vi: tx.vin)
668 if(vi.type() ==
typeid(txin_to_key))
670 const auto &txin = boost::get<txin_to_key>(vi);
672 auto it = m_spent_key_images.find(txin.k_image);
673 CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(),
false,
"failed to find transaction input in key images. img=" << txin.k_image <<
ENDL
674 <<
"transaction id = " << actual_hash);
675 std::unordered_set<crypto::hash>& key_image_set = it->second;
677 <<
"transaction id = " << actual_hash);
679 auto it_in_set = key_image_set.find(actual_hash);
680 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
681 <<
"transaction id = " << actual_hash);
682 key_image_set.erase(it_in_set);
683 if(!key_image_set.size())
686 m_spent_key_images.erase(it);
689 else if (vi.type() ==
typeid(txin_to_key_public))
691 const auto &txin = boost::get<txin_to_key_public>(vi);
695 auto it = m_spent_utxos.find(txin_key);
696 CHECK_AND_ASSERT_MES(it != m_spent_utxos.end(),
false,
"failed to find transaction input in utxos. utxo=" << txin_key <<
ENDL
697 <<
"transaction id = " << actual_hash);
698 std::unordered_set<crypto::hash>& utxo_set = it->second;
700 <<
"transaction id = " << actual_hash);
702 auto it_in_set = utxo_set.find(actual_hash);
703 CHECK_AND_ASSERT_MES(it_in_set != utxo_set.end(),
false,
"transaction id not found in utxo set, utxo=" << txin_key <<
ENDL
704 <<
"transaction id = " << actual_hash);
705 utxo_set.erase(it_in_set);
709 m_spent_utxos.erase(it);
726 auto sorted_it = find_tx_in_sorted_container(
id);
730 LockedTXN
lock(m_blockchain);
732 if (!m_blockchain.get_txpool_tx_meta(
id, meta))
734 MERROR(
"Failed to find tx in txpool");
737 txblob = m_blockchain.get_txpool_tx_blob(
id);
738 auto ci = m_parsed_tx_cache.find(
id);
739 if (ci != m_parsed_tx_cache.end())
745 MERROR(
"Failed to parse tx from txpool");
760 m_blockchain.remove_txpool_tx(
id);
761 m_txpool_weight -= tx_weight;
762 remove_transaction_keyimages(tx,
id);
765 catch (
const std::exception &e)
767 MERROR(
"Failed to remove tx from txpool: " << e.what());
771 if (sorted_it != m_txs_by_fee_and_receive_time.end())
772 m_txs_by_fee_and_receive_time.erase(sorted_it);
779 m_remove_stuck_tx_interval.do_call([
this](){
return remove_stuck_transactions();});
782 sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(
const crypto::hash&
id)
const
784 return std::find_if( m_txs_by_fee_and_receive_time.begin(), m_txs_by_fee_and_receive_time.end()
785 , [&](
const sorted_tx_container::value_type&
a){
786 return a.second == id;
792 bool tx_memory_pool::remove_stuck_transactions()
796 std::list<std::pair<crypto::hash, uint64_t>> remove;
800 if((tx_age > mempool_lifetime && !meta.kept_by_block) ||
803 LOG_PRINT_L1(
"Tx " << txid <<
" removed from tx pool due to outdated, age: " << tx_age );
804 auto sorted_it = find_tx_in_sorted_container(txid);
805 if (sorted_it == m_txs_by_fee_and_receive_time.end())
807 LOG_PRINT_L1(
"Removing tx " << txid <<
" from tx pool, but it was not found in the sorted txs container!");
811 m_txs_by_fee_and_receive_time.erase(sorted_it);
813 m_timed_out_transactions.insert(txid);
814 remove.push_back(std::make_pair(txid, meta.weight));
821 LockedTXN
lock(m_blockchain);
822 for (
const std::pair<crypto::hash, uint64_t> &entry: remove)
828 cryptonote::transaction_prefix tx;
831 MERROR(
"Failed to parse tx from txpool");
837 m_blockchain.remove_txpool_tx(txid);
838 m_txpool_weight -= entry.second;
839 remove_transaction_keyimages(tx, txid);
842 catch (
const std::exception &e)
844 MWARNING(
"Failed to remove stuck transaction: " << txid);
860 txs.reserve(m_blockchain.get_txpool_tx_count());
868 uint32_t mempool_lifetime = m_blockchain.get_mempool_tx_livetime();
875 txs.push_back(std::make_pair(txid, bd));
877 catch (
const std::exception &e)
879 MERROR(
"Failed to get transaction blob from db");
893 const time_t now =
time(NULL);
894 LockedTXN
lock(m_blockchain);
895 for (
auto it = txs.begin(); it != txs.end(); ++it)
900 if (m_blockchain.get_txpool_tx_meta(it->first, meta))
904 m_blockchain.update_txpool_tx(it->first, meta);
907 catch (
const std::exception &e)
909 MERROR(
"Failed to update txpool transaction metadata: " << e.what());
920 return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
927 txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
932 MERROR(
"Failed to parse tx from txpool");
937 txs.push_back(std::move(tx));
939 },
true, include_unrelayed_txes);
946 txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
950 },
false, include_unrelayed_txes);
958 backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
962 },
false, include_unrelayed_txes);
970 std::map<uint64_t, txpool_histo> agebytes;
971 stats.
txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
972 std::vector<uint32_t> weights;
975 weights.push_back(meta.
weight);
992 agebytes[age].bytes += meta.
weight;
998 },
false, include_unrelayed_txes);
1005 std::map<uint64_t, txpool_histo>::iterator it, i2;
1012 for (
size_t n=0; n <= end; n++, it--);
1016 stats.
histo.resize(10);
1023 it = agebytes.end();
1025 delta = now - stats.
oldest;
1026 stats.
histo.resize(factor);
1030 for (i2 = agebytes.begin(); i2 != it; i2++)
1032 size_t i = (i2->first * factor - 1) / delta;
1033 stats.
histo[i].txs += i2->second.txs;
1034 stats.
histo[i].bytes += i2->second.bytes;
1036 for (; i2 != agebytes.end(); i2++)
1038 stats.
histo[factor].txs += i2->second.txs;
1039 stats.
histo[factor].bytes += i2->second.bytes;
1049 tx_infos.reserve(m_blockchain.get_txpool_tx_count());
1050 key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
1058 MERROR(
"Failed to parse tx from txpool");
1081 tx_infos.push_back(std::move(txi));
1083 },
true, include_sensitive_data);
1086 for (
const key_images_container::value_type& kee : m_spent_key_images) {
1088 const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
1093 if (!include_sensitive_data)
1097 if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
1099 MERROR(
"Failed to get tx meta from txpool");
1106 catch (
const std::exception &e)
1108 MERROR(
"Failed to get tx meta from txpool: " << e.what());
1116 key_image_infos.push_back(ki);
1125 tx_infos.reserve(m_blockchain.get_txpool_tx_count());
1126 key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
1132 MERROR(
"Failed to parse tx from txpool");
1152 tx_infos.push_back(txi);
1156 for (
const key_images_container::value_type& kee : m_spent_key_images) {
1157 std::vector<crypto::hash> tx_hashes;
1158 const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
1161 tx_hashes.push_back(tx_id_hash);
1165 key_image_infos[k_image] = std::move(tx_hashes);
1177 for (
const auto& image : key_images)
1179 spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ?
false :
true);
1191 return m_blockchain.get_txpool_tx_blob(
id, txblob);
1193 catch (
const std::exception &e)
1202 m_input_cache.clear();
1203 m_parsed_tx_cache.clear();
1210 m_input_cache.clear();
1211 m_parsed_tx_cache.clear();
1219 return m_blockchain.get_db().txpool_has_tx(
id);
1223 bool tx_memory_pool::key_images_already_spent(
const transaction& tx)
const
1227 for(
const auto& in: tx.
vin)
1231 const auto &tokey_in = boost::get<txin_to_key>(in);
1232 if(have_tx_keyimg_as_spent(tokey_in.k_image))
1242 return have_tx_utxo_as_spent(in);
1245 bool tx_memory_pool::utxo_nonexistent(
const transaction& tx)
const
1249 for(
const auto& in: tx.
vin)
1253 const auto &tokey_in = boost::get<txin_to_key_public>(in);
1254 if(have_tx_utxo_as_spent(tokey_in))
1261 bool tx_memory_pool::have_tx_keyimg_as_spent(
const crypto::key_image& key_im)
const
1264 return m_spent_key_images.end() != m_spent_key_images.find(key_im);
1271 return m_spent_utxos.end() != m_spent_utxos.find(txin_key);
1276 m_transactions_lock.lock();
1281 m_transactions_lock.unlock();
1288 const std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>>::const_iterator i = m_input_cache.find(txid);
1289 if (i != m_input_cache.end())
1291 max_used_block_height = std::get<2>(i->second);
1292 max_used_block_id = std::get<3>(i->second);
1293 tvc = std::get<1>(i->second);
1294 return std::get<0>(i->second);
1297 bool ret = m_blockchain.check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, kept_by_block);
1299 m_input_cache.insert(std::make_pair(txid, std::make_tuple(ret, tvc, max_used_block_height, max_used_block_id)));
1305 struct transction_parser
1308 cryptonote::transaction &operator()()
1313 throw std::runtime_error(
"failed to parse transaction blob");
1323 } lazy_tx(txblob, txid, tx);
1327 if(txd.max_used_block_id == null_hash)
1330 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))
1333 tx_verification_context tvc;
1334 if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{
return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
1336 txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
1337 txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
1342 if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height())
1347 if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
1350 tx_verification_context tvc;
1351 if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{
return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc))
1353 txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
1354 txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
1361 if(tx.version < 3 && m_blockchain.key_images_already_spent(lazy_tx()))
1363 txd.double_spend_seen =
true;
1366 if(tx.version > 2 && m_blockchain.utxo_nonexistent(lazy_tx()))
1368 txd.utxo_nonexistent_seen =
true;
1376 bool tx_memory_pool::have_key_images(
const std::unordered_set<crypto::key_image>& k_images,
const transaction_prefix& tx)
1378 for(
size_t i = 0; i!= tx.vin.size(); i++)
1380 if(tx.vin[i].type() ==
typeid(txin_to_key))
1382 const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1383 if(k_images.count(itk.k_image))
1390 bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images,
const transaction_prefix& tx)
1392 for(
size_t i = 0; i!= tx.vin.size(); i++)
1394 if(tx.vin[i].type() ==
typeid(txin_to_key))
1396 const auto &itk = boost::get<txin_to_key>(tx.vin[i]);
1397 auto i_res = k_images.insert(itk.k_image);
1398 CHECK_AND_ASSERT_MES(i_res.second,
false,
"internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image);
1404 bool tx_memory_pool::have_utxos(
const std::unordered_set<std::string>& utxos,
const transaction_prefix& tx)
1406 for(
size_t i = 0; i!= tx.vin.size(); i++)
1408 if(tx.vin[i].type() ==
typeid(txin_to_key_public))
1410 const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1412 if(utxos.count(txin_key))
1420 bool tx_memory_pool::append_utxos(std::unordered_set<std::string>& utxos,
const transaction_prefix& tx)
1422 for(
size_t i = 0; i!= tx.vin.size(); i++)
1424 if(tx.vin[i].type() ==
typeid(txin_to_key_public))
1426 const auto &itk = boost::get<txin_to_key_public>(tx.vin[i]);
1429 auto i_res = utxos.insert(txin_key);
1430 CHECK_AND_ASSERT_MES(i_res.second,
false,
"internal error: utxo pool cache - inserted duplicate image in set: " << txin_key);
1436 void tx_memory_pool::mark_double_spend_or_nonexistent_utxo(
const transaction &tx)
1440 bool changed =
false;
1441 LockedTXN
lock(m_blockchain);
1442 for(
size_t i = 0; i!= tx.vin.size(); i++)
1444 if(tx.vin[i].type() ==
typeid(txin_to_key))
1447 const key_images_container::const_iterator it = m_spent_key_images.find(itk.k_image);
1448 if (it != m_spent_key_images.end())
1452 txpool_tx_meta_t meta;
1453 if (!m_blockchain.get_txpool_tx_meta(txid, meta))
1455 MERROR(
"Failed to find tx meta in txpool");
1459 if (!meta.double_spend_seen)
1461 MDEBUG(
"Marking " << txid <<
" as double spending " << itk.k_image);
1462 meta.double_spend_seen =
true;
1466 m_blockchain.update_txpool_tx(txid, meta);
1468 catch (
const std::exception &e)
1470 MERROR(
"Failed to update tx meta: " << e.what());
1477 else if (tx.vin[i].type() ==
typeid(txin_to_key_public))
1481 const utxos_container::const_iterator it = m_spent_utxos.find(txin_key);
1482 if (it != m_spent_utxos.end())
1486 txpool_tx_meta_t meta;
1487 if (!m_blockchain.get_txpool_tx_meta(txid, meta))
1489 MERROR(
"Failed to find tx meta in txpool");
1493 if (!meta.double_spend_seen)
1495 MDEBUG(
"Marking " << txid <<
" as double spending " << txin_key);
1496 meta.utxo_nonexistent_seen =
true;
1500 m_blockchain.update_txpool_tx(txid, meta);
1502 catch (
const std::exception &e)
1504 MERROR(
"Failed to update tx meta: " << e.what());
1523 std::stringstream ss;
1527 ss <<
"id: " << txid << std::endl;
1528 if (!short_format) {
1532 MERROR(
"Failed to parse tx from txpool");
1537 ss <<
"blob_size: " << (short_format ?
"-" : std::to_string(txblob->size())) << std::endl
1538 <<
"weight: " << meta.
weight << std::endl
1540 <<
"kept_by_block: " << (meta.
kept_by_block ?
'T' :
'F') << std::endl
1559 uint64_t best_coinbase = 0, coinbase = 0;
1564 get_block_reward(median_weight, total_weight, already_generated_coins, best_coinbase,
version, m_blockchain.get_current_blockchain_height(), m_blockchain.get_nettype());
1569 size_t max_total_weight =
version >= 5 ? max_total_weight_v5 : max_total_weight_pre_v5;
1570 std::unordered_set<crypto::key_image> k_images;
1571 std::unordered_set<std::string> utxos;
1573 LOG_PRINT_L2(
"Filling block template, median weight " << median_weight <<
", " << m_txs_by_fee_and_receive_time.size() <<
" txes in the pool");
1575 LockedTXN
lock(m_blockchain);
1577 auto sorted_it = m_txs_by_fee_and_receive_time.begin();
1578 for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
1581 if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
1583 MERROR(
" failed to find tx meta");
1586 LOG_PRINT_L2(
"Considering " << sorted_it->second <<
", weight " << meta.
weight <<
", current block weight " << total_weight <<
"/" << max_total_weight <<
", current coinbase " <<
print_etn(best_coinbase));
1589 if (max_total_weight < total_weight + meta.
weight)
1601 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()))
1606 coinbase = block_reward + fee + meta.
fee;
1607 if (coinbase < template_accept_threshold(best_coinbase))
1617 if (total_weight > median_weight)
1634 ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
1636 catch (
const std::exception &e)
1638 MERROR(
"Failed to check transaction readiness: " << e.what());
1641 if (memcmp(&original_meta, &meta,
sizeof(meta)))
1645 m_blockchain.update_txpool_tx(sorted_it->second, meta);
1647 catch (
const std::exception &e)
1649 MERROR(
"Failed to update tx meta: " << e.what());
1658 if (have_key_images(k_images, tx))
1663 if (have_utxos(utxos, tx))
1669 bl.
tx_hashes.push_back(sorted_it->second);
1670 total_weight += meta.
weight;
1672 best_coinbase = coinbase;
1673 append_key_images(k_images, tx);
1674 append_utxos(utxos, tx);
1675 LOG_PRINT_L2(
" added, new block weight " << total_weight <<
"/" << max_total_weight <<
", coinbase " <<
print_etn(best_coinbase));
1679 expected_reward = best_coinbase;
1681 << total_weight <<
"/" << max_total_weight <<
", coinbase " <<
print_etn(best_coinbase)
1682 <<
" (including " <<
print_etn(fee) <<
" in fees)");
1690 size_t tx_weight_limit = get_transaction_weight_limit(
version);
1691 std::unordered_set<crypto::hash> remove;
1693 m_txpool_weight = 0;
1695 m_txpool_weight += meta.
weight;
1696 if (meta.
weight > tx_weight_limit) {
1697 LOG_PRINT_L1(
"Transaction " << txid <<
" is too big (" << meta.
weight <<
" bytes), removing it from pool");
1698 remove.insert(txid);
1700 else if (m_blockchain.have_tx(txid)) {
1701 LOG_PRINT_L1(
"Transaction " << txid <<
" is in the blockchain, removing it from pool");
1702 remove.insert(txid);
1707 size_t n_removed = 0;
1708 if (!remove.empty())
1710 LockedTXN
lock(m_blockchain);
1719 MERROR(
"Failed to parse tx from txpool");
1723 m_blockchain.remove_txpool_tx(txid);
1725 remove_transaction_keyimages(tx, txid);
1726 auto sorted_it = find_tx_in_sorted_container(txid);
1727 if (sorted_it == m_txs_by_fee_and_receive_time.end())
1729 LOG_PRINT_L1(
"Removing tx " << txid <<
" from tx pool, but it was not found in the sorted txs container!");
1733 m_txs_by_fee_and_receive_time.erase(sorted_it);
1737 catch (
const std::exception &e)
1739 MERROR(
"Failed to remove invalid tx from pool");
1756 m_txs_by_fee_and_receive_time.clear();
1757 m_spent_key_images.clear();
1758 m_spent_utxos.clear();
1759 m_txpool_weight = 0;
1760 std::vector<crypto::hash> remove;
1764 for (
int pass = 0; pass < 2; ++pass)
1766 const bool kept = pass == 1;
1773 MWARNING(
"Failed to parse tx from txpool, removing");
1774 remove.push_back(txid);
1779 MFATAL(
"Failed to insert key images from txpool tx");
1784 MFATAL(
"Failed to insert utxos from txpool tx");
1787 m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.
fee / (
double)meta.
weight, meta.
receive_time), txid);
1788 m_txpool_weight += meta.
weight;
1794 if (!remove.empty())
1796 LockedTXN
lock(m_blockchain);
1797 for (
const auto &txid: remove)
1801 m_blockchain.remove_txpool_tx(txid);
1803 catch (
const std::exception &e)
1805 MWARNING(
"Failed to remove corrupt transaction: " << txid);
bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const
bool for_all_txpool_txes(std::function< bool(const crypto::hash &, const txpool_tx_meta_t &, const cryptonote::blobdata *)>, bool include_blob=false, bool include_unrelayed_txes=true) const
uint32_t get_mempool_tx_livetime() const
std::vector< uint8_t > extra
std::vector< txin_v > vin
std::vector< tx_out > vout
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
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.
void set_relayed(const std::vector< std::pair< crypto::hash, cryptonote::blobdata > > &txs)
tell the pool that certain transactions were just relayed
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
bool utxo_spent_in_pool(const txin_to_key_public &in) const
get a summary statistics of all transaction hashes in the pool
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
tx_memory_pool(Blockchain &bchs)
Constructor.
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_transaction(const crypto::hash &h, cryptonote::blobdata &txblob) const
get a specific transaction from 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 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
#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
void * memcpy(void *a, const void *b, size_t c)
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
void cn_fast_hash(const void *data, size_t length, char *hash)
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig)
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
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
crypto::hash get_transaction_hash(const transaction &t)
bool check_outs_valid(const transaction &tx)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
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)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
unsigned __int64 uint64_t
crypto::public_key m_spend_public_key
account_public_address address
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_bad_bridge_source_address
bool m_bad_bridge_ownership_sig
bool m_verification_impossible
bool m_portal_outbound_tx
bool m_bad_bridge_smartchain_address
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)
#define DISABLE_VS_WARNINGS(w)