Electroneum
Loading...
Searching...
No Matches
cryptonote::tx_memory_pool Class Reference

Transaction pool, handles transactions which are not part of a block. More...

#include <tx_pool.h>

Inheritance diagram for cryptonote::tx_memory_pool:
Collaboration diagram for cryptonote::tx_memory_pool:

Classes

struct  tx_details
 information about a single transaction More...

Public Member Functions

 tx_memory_pool (Blockchain &bchs)
 Constructor.
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 add_tx (transaction &tx, tx_verification_context &tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
 add a transaction to the transaction 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 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 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
void on_idle ()
 action to take periodically
void lock () const
 locks the transaction pool
void unlock () const
 unlocks the transaction pool
bool init (size_t max_txpool_weight=0)
 loads pool state (if any) from disk, and initializes pool
bool deinit ()
 attempts to save the transaction pool state to disk
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 get_transactions (std::vector< transaction > &txs, bool include_unrelayed_txes=true) const
 get a list of all transactions 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
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
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
bool utxo_spent_in_pool (const txin_to_key_public &in) const
 get a summary statistics of all transaction hashes in 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 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 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 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
void set_relayed (const std::vector< std::pair< crypto::hash, cryptonote::blobdata > > &txs)
 tell the pool that certain transactions were just relayed
size_t get_transactions_count (bool include_unrelayed_txes=true) const
 get the total number of transactions in the pool
std::string print_pool (bool short_format) const
 get a string containing human-readable pool information
size_t validate (uint8_t version)
 remove transactions from the pool which are no longer valid
uint64_t cookie () const
 return the cookie
size_t get_txpool_weight () const
 get the cumulative txpool weight in bytes
void set_txpool_max_weight (size_t bytes)
 set the max cumulative txpool weight in bytes

Detailed Description

Transaction pool, handles transactions which are not part of a block.

This class handles all transactions which have been received, but not as part of a block.

This handling includes: storing the transactions organizing the transactions by fee per weight unit taking/giving transactions to and from various other components saving the transactions to disk on shutdown helping create a new block template by choosing transactions for it

Definition at line 94 of file tx_pool.h.

Constructor & Destructor Documentation

◆ tx_memory_pool()

cryptonote::tx_memory_pool::tx_memory_pool ( Blockchain & bchs)

Constructor.

Parameters
bchsa Blockchain class instance, for getting chain info

Definition at line 117 of file tx_pool.cpp.

117 : m_blockchain(bchs), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_cookie(0)
118 {
119
120 }
#define DEFAULT_TXPOOL_MAX_WEIGHT
Here is the call graph for this function:
Here is the caller graph for this function:

Member Function Documentation

◆ add_tx() [1/2]

bool cryptonote::tx_memory_pool::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 )

Parameters
idthe transaction's hash
tx_weightthe transaction's weight

Definition at line 122 of file tx_pool.cpp.

123 {
124 // this should already be called with that lock, but let's make it explicit for clarity
125 CRITICAL_REGION_LOCAL(m_transactions_lock);
126
128 if (tx.version == 0)
129 {
130 // v0 never accepted
131 LOG_PRINT_L1("transaction version 0 is invalid");
132 tvc.m_verification_failed = true;
133 return false;
134 }
135
136 // we do not accept transactions that timed out before, unless they're
137 // kept_by_block
138 if (!kept_by_block && m_timed_out_transactions.find(id) != m_timed_out_transactions.end())
139 {
140 // not clear if we should set that, since verifivation (sic) did not fail before, since
141 // the tx was accepted before timing out.
142 tvc.m_verification_failed = true;
143 return false;
144 }
145
147 {
148 tvc.m_verification_failed = true;
149 tvc.m_invalid_input = true;
150 return false;
151 }
152
153 if(!check_outs_valid(tx))
154 {
155 tvc.m_verification_failed = true;
156 tvc.m_invalid_output = true;
157 return false;
158 }
159
160 // fee per kilobyte, size rounded up.
161 uint64_t fee = 0;
162
163 uint64_t inputs_amount = 0;
164 if(!get_inputs_etn_amount(tx, inputs_amount))
165 {
166 tvc.m_verification_failed = true;
167 return false;
168 }
169
170 uint64_t outputs_amount = get_outs_etn_amount(tx);
171 fee = inputs_amount - outputs_amount;
172
173 if(tx.version == 3 && m_blockchain.get_current_blockchain_height() > (m_blockchain.get_nettype() == MAINNET ? 1811310 : 1455270)) {
174 if(outputs_amount != inputs_amount)
175 {
176 LOG_PRINT_L1("transaction fee isnt zero: outputs_amount != inputs_amount, rejecting.");
177 tvc.m_verification_failed = true;
178 return false;
179 }
180
181 if(fee != 0){
182 LOG_PRINT_L1("We are migrating to aurelius and this transaction should have zero fee and it doesn't, rejecting.");
183 tvc.m_verification_failed = true;
184 return false;
185 }
186 }else{
187
188 if(outputs_amount > inputs_amount)
189 {
190 LOG_PRINT_L1("transaction use more ETN than it has: use " << print_etn(outputs_amount) << ", have " << print_etn(inputs_amount));
191 tvc.m_verification_failed = true;
192 tvc.m_overspend = true;
193 return false;
194 }
195 else if(tx.version != 2 && outputs_amount == inputs_amount)
196 {
197
198 // v1 & v2 tx ins/outs semantics are checked in the same way regardless of our chains height or the network height
199 if(tx.version == 1) {
200 LOG_PRINT_L1("v1 transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
201 tvc.m_verification_failed = true;
202 tvc.m_fee_too_low = true;
203 return false;
204 }
205
206 // for v3 these are fee paying before the final fork, but feeless afterwards.
207 // the only way of splitting the two up is by checking the destination, because after the final hard fork,
208 // transactions can only go to the bridge (consensus rule elsewhere)
209 if(tx.version == 3){
210 //check to see if all outputs are to the bridge address. if so, waive fee, otherwise if feeless return false
211 std::string portal_address_viewkey_hex_str;
212 std::string portal_address_spendkey_hex_str;
213 if(m_blockchain.get_nettype() == MAINNET){
214 portal_address_viewkey_hex_str = "2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
215 portal_address_spendkey_hex_str = "8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
216 }else{
217 portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
218 portal_address_spendkey_hex_str = "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3"; //
219 }
220 bool is_sc_migration = true;
221 for (auto output: tx.vout){
222 const auto out = boost::get<txout_to_key_public>(output.target);
223 std::string out_spendkey_str = epee::string_tools::pod_to_hex(out.address.m_spend_public_key.data);
224 std::string out_viewkey_str = epee::string_tools::pod_to_hex(out.address.m_view_public_key.data);
225
226 // If we found an output not going to the bridge, the tx is certainly pre the final hard fork.
227 // so check tx ins/outs semantics here and error/break loop as needed.
228 if(out_spendkey_str != portal_address_spendkey_hex_str || out_viewkey_str != portal_address_viewkey_hex_str){
229 is_sc_migration = false;
230 if(inputs_amount <= outputs_amount){
231 LOG_PRINT_L1("pre smartchain migration version 3 tx with wrong amounts: ins " << print_etn(inputs_amount) << ", outs " << print_etn(outputs_amount) << ", rejected for tx id= "
232 << get_transaction_hash(tx));
233 return false;
234 }else {
235 break; // we only need to check the overall tx once
236 }
237 }
238 }
239
240 if (is_sc_migration == true && inputs_amount != outputs_amount){
241 LOG_PRINT_L1("version 3 smartchain migration tx should be feeless but has wrong amounts: ins " << print_etn(inputs_amount) << ", outs " << print_etn(outputs_amount) << ", rejected for tx id= "
242 << get_transaction_hash(tx));
243 return false;
244 }
245 }
246 }
247
248 if(tx.version == 2 && fee != 0) //Assure 0 fee tx v2 (migration tx)
249 {
250 LOG_PRINT_L1("transaction v2 fee is greater than zero, rejecting.");
251 tvc.m_verification_failed = true;
252 return false;
253 }
254
255 if (tx.version != 2 && !kept_by_block && !m_blockchain.check_fee(tx_weight, fee))
256 {
257 tvc.m_verification_failed = true;
258 tvc.m_fee_too_low = true;
259 return false;
260 }
261 }
262
263 size_t tx_weight_limit = get_transaction_weight_limit(version);
264 if ((!kept_by_block || version >= HF_VERSION_PER_BYTE_FEE) && tx_weight > tx_weight_limit)
265 {
266 LOG_PRINT_L1("transaction is too heavy: " << tx_weight << " bytes, maximum weight: " << tx_weight_limit);
267 tvc.m_verification_failed = true;
268 tvc.m_too_big = true;
269 return false;
270 }
271
272 // if the transaction came from a block popped from the chain,
273 // don't check if we have its key images as spent.
274 // TODO: Investigate why not?
275 if(!kept_by_block)
276 {
277 if(tx.version <= 2) {
278 if (key_images_already_spent(tx)) {
279 mark_double_spend_or_nonexistent_utxo(tx);
280 LOG_PRINT_L1("Transaction with id= " << id << " used already spent key images");
281 tvc.m_verification_failed = true;
282 tvc.m_double_spend = true;
283 return false;
284 }
285 }
286 if(tx.version > 2) {
287 if (utxo_nonexistent(tx)) {
288 mark_double_spend_or_nonexistent_utxo(tx);
289 LOG_PRINT_L1("Transaction with id= " << id << " used nonexistent utxos");
290 tvc.m_verification_failed = true;
291 tvc.m_utxo_nonexistent = true;
292 return false;
293 }
294 }
295 }
296
297 if (!m_blockchain.check_tx_outputs(tx, tvc))
298 {
299 LOG_PRINT_L1("Transaction with id= "<< id << " has at least one invalid output");
300 tvc.m_verification_failed = true;
301 tvc.m_invalid_output = true;
302 return false;
303 }
304
305 // assume failure during verification steps until success is certain
306 tvc.m_verification_failed = true;
307
308 time_t receive_time = time(nullptr);
309
310 crypto::hash max_used_block_id = null_hash;
311 uint64_t max_used_block_height = 0;
312 cryptonote::txpool_tx_meta_t meta;
313
314 bool ch_inp_res = check_tx_inputs([&tx]()->cryptonote::transaction&{ return tx; }, id, max_used_block_height, max_used_block_id, tvc, kept_by_block);
315
316 if(tx.version == 3 && m_blockchain.get_current_blockchain_height() > (m_blockchain.get_nettype() == MAINNET ? 1811310 : 1455270)) {
317
318 //testing
319 //std::string hex_hash = "b166158ee98c5b01252ef6180a1d1ec5f8eced68c947e1a0f2444cf3b9730371";
320 //crypto::hash testing_tx_hash;
321 //epee::string_tools::hex_to_pod(hex_hash, testing_tx_hash);
322 //transaction testing_tx;
323 //m_blockchain.get_db().get_tx(testing_tx_hash, testing_tx);
324
325 // Block all transactions that don't have valid migration information in the tx extra
326 std::vector<tx_extra_field> tx_extra_fields;
327 //parse_tx_extra(tx.extra, tx_extra_fields);
328 parse_tx_extra(tx.extra, tx_extra_fields);
329 cryptonote::tx_extra_bridge_source_address bridge_source_address;
330 cryptonote::tx_extra_bridge_smartchain_address bridge_smartchain_address;
331 find_tx_extra_field_by_type(tx_extra_fields, bridge_source_address);
332 find_tx_extra_field_by_type(tx_extra_fields, bridge_smartchain_address);
333
334 address_parse_info parse_info_dummy;
335 if(!cryptonote::get_account_address_from_str(parse_info_dummy, m_blockchain.get_nettype(), bridge_source_address.data)){
336 tvc.m_verification_failed = true;
337 tvc.m_bad_bridge_source_address = true;
338 return false;
339 }
340
341 // Verify ownership signature: proves the sender controls the spend key of bridge_source_address
342 cryptonote::tx_extra_bridge_ownership_sig bridge_ownership_sig;
343 if(!find_tx_extra_field_by_type(tx_extra_fields, bridge_ownership_sig) || bridge_ownership_sig.data.size() != sizeof(crypto::signature)){
344 tvc.m_verification_failed = true;
345 tvc.m_bad_bridge_ownership_sig = true;
346 return false;
347 }
348 std::string sig_message = bridge_source_address.data + bridge_smartchain_address.data;
349 crypto::hash sig_hash;
350 crypto::cn_fast_hash(sig_message.data(), sig_message.size(), sig_hash);
351 crypto::signature ownership_sig;
352 memcpy(&ownership_sig, bridge_ownership_sig.data.data(), sizeof(crypto::signature));
353 if(!crypto::check_signature(sig_hash, parse_info_dummy.address.m_spend_public_key, ownership_sig)){
354 tvc.m_verification_failed = true;
355 tvc.m_bad_bridge_ownership_sig = true;
356 return false;
357 }
358
359 // The regular expression pattern for a valid Ethereum address
360 bool valid_smartchain_address = true;
361 std::string string_smartchain_address = bridge_smartchain_address.data;
362 //string_smartchain_address = "0xc1912fEE45d61C87Cc5EA59DaE31190FFFFf232d";
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;
366
367
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);
372 });
373
374 if(isMixedCase && valid_smartchain_address != false){ // if it's mixed case, we have to do extra checks
375 // Convert the address to lowercase for hashing
376 std::string lower_address = string_smartchain_address.substr(2);
377 std::transform(lower_address.begin(), lower_address.end(), lower_address.begin(), ::tolower);
378
379 unsigned char hashed_lower[32];
380 keccak(reinterpret_cast<const uint8_t *>(lower_address.data()), 40, hashed_lower, 32);
381 std::string address_hash = epee::string_tools::pod_to_hex(hashed_lower); // should be 0x12ed7467c3852e6b2Bd3C22AF694be8DF7637B10.
382
383 std::string hash;
384 for (size_t i = 0; i < lower_address.length(); i++) {
385 if (std::isdigit(lower_address[i])) {
386 hash += lower_address[i];
387 }
388 else if (address_hash[i] >= '8') {
389 hash += std::toupper(lower_address[i]);
390 }
391 else {
392 hash += lower_address[i];
393 }
394 }
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;
399 }
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;
404 }
405 }
406 else if (checksum[i - 2] != string_smartchain_address[i]) {
407 valid_smartchain_address = false;
408 }
409 }
410
411 } //end of is mixed case
412
413 if(!valid_smartchain_address){
414 tvc.m_verification_failed = true;
415 tvc.m_bad_bridge_smartchain_address = true;
416 return false;
417 }
418 //BLOCK ALL TX NOT GOING TO THE PORTAL 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";
424 }else{
425 portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
426 portal_address_spendkey_hex_str = "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3"; //
427 }
428
429 for (auto output: tx.vout){
430 const auto out = boost::get<txout_to_key_public>(output.target);
431 std::string out_spendkey_str = epee::string_tools::pod_to_hex(out.address.m_spend_public_key.data);
432 std::string out_viewkey_str = epee::string_tools::pod_to_hex(out.address.m_view_public_key.data);
433 if(out_spendkey_str != portal_address_spendkey_hex_str || out_viewkey_str != portal_address_viewkey_hex_str){
434 tvc.m_verification_failed = true;
435 tvc.m_portal_outbound_tx = true;
436 return false;
437 }
438 }
439 }
440
441 if(!ch_inp_res)
442 {
443 // if the transaction was valid before (kept_by_block), then it
444 // may become valid again, so ignore the failed inputs check.
445 if(kept_by_block)
446 {
447 meta.weight = tx_weight;
448 meta.fee = fee;
449 meta.max_used_block_id = null_hash;
450 meta.max_used_block_height = 0;
451 meta.last_failed_height = 0;
452 meta.last_failed_id = null_hash;
453 meta.kept_by_block = kept_by_block;
454 meta.receive_time = receive_time;
455 meta.last_relayed_time = time(NULL);
456 meta.relayed = relayed;
457 meta.do_not_relay = do_not_relay;
458 meta.double_spend_seen = key_images_already_spent(tx);
459 meta.utxo_nonexistent_seen = utxo_nonexistent(tx);
460 meta.bf_padding = 0;
461 memset(meta.padding, 0, sizeof(meta.padding));
462 try
463 {
464 if (kept_by_block)
465 m_parsed_tx_cache.insert(std::make_pair(id, tx));
466 CRITICAL_REGION_LOCAL1(m_blockchain);
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)))
470 return false;
471 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
472 lock.commit();
473 }
474 catch (const std::exception &e)
475 {
476 MERROR("transaction already exists at inserting in memory pool: " << e.what());
477 return false;
478 }
479 tvc.m_verification_impossible = true;
480 tvc.m_added_to_pool = true;
481 }else
482 {
483 LOG_PRINT_L1("tx used wrong inputs, rejected");
484 tvc.m_verification_failed = true;
485 tvc.m_invalid_input = true;
486 return false;
487 }
488 }else
489 {
490 //update transactions container
491 meta.weight = tx_weight;
492 meta.kept_by_block = kept_by_block;
493 meta.fee = fee;
494 meta.max_used_block_id = max_used_block_id;
495 meta.max_used_block_height = max_used_block_height;
496 meta.last_failed_height = 0;
497 meta.last_failed_id = null_hash;
498 meta.receive_time = receive_time;
499 meta.last_relayed_time = time(NULL);
500 meta.relayed = relayed;
501 meta.do_not_relay = do_not_relay;
502 meta.double_spend_seen = false;
503 meta.utxo_nonexistent_seen = false;
504 meta.bf_padding = 0;
505 memset(meta.padding, 0, sizeof(meta.padding));
506
507 try
508 {
509 if (kept_by_block)
510 m_parsed_tx_cache.insert(std::make_pair(id, tx));
511 CRITICAL_REGION_LOCAL1(m_blockchain);
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)))
516 return false;
517 m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
518 lock.commit();
519 }
520 catch (const std::exception &e)
521 {
522 MERROR("internal error: transaction already exists at inserting in memory pool: " << e.what());
523 return false;
524 }
525 tvc.m_added_to_pool = true;
526
527 if(!do_not_relay)
528 tvc.m_should_be_relayed = true;
529 }
530
531 tvc.m_verification_failed = false;
532 m_txpool_weight += tx_weight;
533
534 ++m_cookie;
535
536 MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)tx_weight));
537
538 prune(m_txpool_max_weight);
539
540 return true;
541 }
uint8_t version
time_t time
void lock() const
locks the transaction pool
Definition tx_pool.cpp:1274
bool add_tx(transaction &tx, const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context &tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
Definition tx_pool.cpp:122
#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 MERROR(x)
Definition misc_log_ex.h:73
#define LOG_PRINT_L1(x)
#define MINFO(x)
Definition misc_log_ex.h:75
POD_CLASS signature
Definition crypto.h:108
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)
Definition crypto.h:295
POD_CLASS hash
Definition hash.h:50
uint64_t get_outs_etn_amount(const transaction &tx)
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 get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
bool check_inputs_types_supported(const transaction &tx)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
std::string pod_to_hex(const t_pod_type &s)
#define PERF_TIMER(name)
Definition perf_timer.h:82
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
#define CRITICAL_REGION_LOCAL1(x)
Definition syncobj.h:230
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:228
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_tx() [2/2]

bool cryptonote::tx_memory_pool::add_tx ( transaction & tx,
tx_verification_context & tvc,
bool kept_by_block,
bool relayed,
bool do_not_relay,
uint8_t version )

add a transaction to the transaction pool

Most likely the transaction will come from the network, but it is also possible for transactions to come from popped blocks during a reorg, or from local clients creating a transaction and submitting it to the network

Parameters
txthe transaction to be added
tvcreturn-by-reference status about the transaction verification
kept_by_blockhas this transaction been in a block?
relayedwas this transaction from the network or a local client?
do_not_relayto avoid relaying the transaction to the network
versionthe version used to create the transaction
Returns
true if the transaction passes validations, otherwise false

◆ check_for_key_images()

bool cryptonote::tx_memory_pool::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

Parameters
key_images[in] vector of key images to check
spent[out] vector of bool to return
Returns
true

Definition at line 1170 of file tx_pool.cpp.

1171 {
1172 CRITICAL_REGION_LOCAL(m_transactions_lock);
1173 CRITICAL_REGION_LOCAL1(m_blockchain);
1174
1175 spent.clear();
1176
1177 for (const auto& image : key_images)
1178 {
1179 spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ? false : true);
1180 }
1181
1182 return true;
1183 }

◆ cookie()

uint64_t cryptonote::tx_memory_pool::cookie ( ) const
inline

return the cookie

Returns
the cookie

Definition at line 381 of file tx_pool.h.

381{ return m_cookie; }

◆ deinit()

bool cryptonote::tx_memory_pool::deinit ( )

attempts to save the transaction pool state to disk

Currently fails (returns false) if the data directory from init() does not exist and cannot be created, but returns true even if saving to disk is unsuccessful.

Returns
true in most cases (see above)

Definition at line 1819 of file tx_pool.cpp.

1820 {
1821 return true;
1822 }

◆ fill_block_template()

bool cryptonote::tx_memory_pool::fill_block_template ( block & bl,
size_t median_weight,
uint64_t already_generated_coins,
size_t & total_weight,
uint64_t & fee,
uint64_t & expected_reward,
uint8_t version )

Chooses transactions for a block to include.

Parameters
blreturn-by-reference the block to fill in with transactions
median_weightthe current median block weight
already_generated_coinsthe current total number of coins "minted"
total_weightreturn-by-reference the total weight of the new block
feereturn-by-reference the total of fees from the included transactions
expected_rewardreturn-by-reference the total reward awarded to the miner finding this block, including transaction fees
versionhard fork version to use for consensus rules
Returns
true

Definition at line 1554 of file tx_pool.cpp.

1555 {
1556 CRITICAL_REGION_LOCAL(m_transactions_lock);
1557 CRITICAL_REGION_LOCAL1(m_blockchain);
1558
1559 uint64_t best_coinbase = 0, coinbase = 0;
1560 total_weight = 0;
1561 fee = 0;
1562
1563 //baseline empty block
1564 get_block_reward(median_weight, total_weight, already_generated_coins, best_coinbase, version, m_blockchain.get_current_blockchain_height(), m_blockchain.get_nettype());
1565
1566
1567 size_t max_total_weight_pre_v5 = (130 * median_weight) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
1568 size_t max_total_weight_v5 = 2 * median_weight - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
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;
1572
1573 LOG_PRINT_L2("Filling block template, median weight " << median_weight << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
1574
1575 LockedTXN lock(m_blockchain);
1576
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)
1579 {
1580 txpool_tx_meta_t meta;
1581 if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
1582 {
1583 MERROR(" failed to find tx meta");
1584 continue;
1585 }
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));
1587
1588 // Can not exceed maximum block weight
1589 if (max_total_weight < total_weight + meta.weight)
1590 {
1591 LOG_PRINT_L2(" would exceed maximum block weight");
1592 continue;
1593 }
1594
1595 // start using the optimal filling algorithm from v5
1596 if (version >= 5)
1597 {
1598 // If we're getting lower coinbase tx,
1599 // stop including more tx
1600 uint64_t block_reward;
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()))
1602 {
1603 LOG_PRINT_L2(" would exceed maximum block weight");
1604 continue;
1605 }
1606 coinbase = block_reward + fee + meta.fee;
1607 if (coinbase < template_accept_threshold(best_coinbase))
1608 {
1609 LOG_PRINT_L2(" would decrease coinbase to " << print_etn(coinbase));
1610 continue;
1611 }
1612 }
1613 else
1614 {
1615 // If we've exceeded the penalty free weight,
1616 // stop including more tx
1617 if (total_weight > median_weight)
1618 {
1619 LOG_PRINT_L2(" would exceed median block weight");
1620 break;
1621 }
1622 }
1623
1624 cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second);
1625 cryptonote::transaction tx;
1626
1627 // Skip transactions that are not ready to be
1628 // included into the blockchain or that are
1629 // missing key images
1630 const cryptonote::txpool_tx_meta_t original_meta = meta;
1631 bool ready = false;
1632 try
1633 {
1634 ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx);
1635 }
1636 catch (const std::exception &e)
1637 {
1638 MERROR("Failed to check transaction readiness: " << e.what());
1639 // continue, not fatal
1640 }
1641 if (memcmp(&original_meta, &meta, sizeof(meta)))
1642 {
1643 try
1644 {
1645 m_blockchain.update_txpool_tx(sorted_it->second, meta);
1646 }
1647 catch (const std::exception &e)
1648 {
1649 MERROR("Failed to update tx meta: " << e.what());
1650 // continue, not fatal
1651 }
1652 }
1653 if (!ready)
1654 {
1655 LOG_PRINT_L2(" not ready to go");
1656 continue;
1657 }
1658 if (have_key_images(k_images, tx))
1659 {
1660 LOG_PRINT_L2(" key images already seen");
1661 continue;
1662 }
1663 if (have_utxos(utxos, tx))
1664 {
1665 LOG_PRINT_L2(" utxos already seen");
1666 continue;
1667 }
1668
1669 bl.tx_hashes.push_back(sorted_it->second);
1670 total_weight += meta.weight;
1671 fee += meta.fee;
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));
1676 }
1677 lock.commit();
1678
1679 expected_reward = best_coinbase;
1680 LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight "
1681 << total_weight << "/" << max_total_weight << ", coinbase " << print_etn(best_coinbase)
1682 << " (including " << print_etn(fee) << " in fees)");
1683 return true;
1684 }
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE
#define LOG_PRINT_L2(x)
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 blobdata
Here is the call graph for this function:

◆ get_pool_for_rpc()

bool cryptonote::tx_memory_pool::get_pool_for_rpc ( std::vector< cryptonote::rpc::tx_in_pool > & tx_infos,
cryptonote::rpc::key_images_with_tx_hashes & key_image_infos ) const

get information about all transactions and key images in the pool

see documentation on tx_in_pool and key_images_with_tx_hashes for more details

Parameters
tx_infos[out] the transactions' information
key_image_infos[out] the spent key images' information
Returns
true

Definition at line 1121 of file tx_pool.cpp.

1122 {
1123 CRITICAL_REGION_LOCAL(m_transactions_lock);
1124 CRITICAL_REGION_LOCAL1(m_blockchain);
1125 tx_infos.reserve(m_blockchain.get_txpool_tx_count());
1126 key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
1127 m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
1128 cryptonote::rpc::tx_in_pool txi;
1129 txi.tx_hash = txid;
1130 if (!parse_and_validate_tx_from_blob(*bd, txi.tx))
1131 {
1132 MERROR("Failed to parse tx from txpool");
1133 // continue
1134 return true;
1135 }
1136 txi.tx.set_hash(txid);
1137 txi.blob_size = bd->size();
1138 txi.weight = meta.weight;
1139 txi.fee = meta.fee;
1140 txi.kept_by_block = meta.kept_by_block;
1141 txi.max_used_block_height = meta.max_used_block_height;
1142 txi.max_used_block_hash = meta.max_used_block_id;
1143 txi.last_failed_block_height = meta.last_failed_height;
1144 txi.last_failed_block_hash = meta.last_failed_id;
1145 txi.receive_time = meta.receive_time;
1146 txi.relayed = meta.relayed;
1147 txi.last_relayed_time = meta.last_relayed_time;
1148 txi.do_not_relay = meta.do_not_relay;
1149 txi.double_spend_seen = meta.double_spend_seen;
1150 txi.nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
1151
1152 tx_infos.push_back(txi);
1153 return true;
1154 }, true, false);
1155
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;
1159 for (const crypto::hash& tx_id_hash : kei_image_set)
1160 {
1161 tx_hashes.push_back(tx_id_hash);
1162 }
1163
1164 const crypto::key_image& k_image = kee.first;
1165 key_image_infos[k_image] = std::move(tx_hashes);
1166 }
1167 return true;
1168 }
void set_hash(const crypto::hash &h)
POD_CLASS key_image
Definition crypto.h:105
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
Here is the call graph for this function:

◆ get_relayable_transactions()

bool cryptonote::tx_memory_pool::get_relayable_transactions ( std::vector< std::pair< crypto::hash, cryptonote::blobdata > > & txs) const

get a list of all relayable transactions and their hashes

"relayable" in this case means: nonzero fee hasn't been relayed too recently isn't old enough that relaying it is considered harmful Note a transaction can be "relayable" even if do_not_relay is true

Parameters
txsreturn-by-reference the transactions and their hashes
Returns
true

Definition at line 855 of file tx_pool.cpp.

856 {
857 CRITICAL_REGION_LOCAL(m_transactions_lock);
858 CRITICAL_REGION_LOCAL1(m_blockchain);
859 const uint64_t now = time(NULL);
860 txs.reserve(m_blockchain.get_txpool_tx_count());
861 m_blockchain.for_all_txpool_txes([this, now, &txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
862 // 0 fee transactions are never relayed
863 if(!meta.do_not_relay && now - meta.last_relayed_time > get_relay_delay(now, meta.receive_time))
864 {
865 // if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
866 // mentioned by smooth where nodes would flush txes at slightly different times, causing
867 // flushed txes to be re-added when received from a node which was just about to flush it
868 uint32_t mempool_lifetime = m_blockchain.get_mempool_tx_livetime();
869 uint64_t max_age = meta.kept_by_block ? CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME : mempool_lifetime;
870 if (now - meta.receive_time <= max_age / 2)
871 {
872 try
873 {
874 cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
875 txs.push_back(std::make_pair(txid, bd));
876 }
877 catch (const std::exception &e)
878 {
879 MERROR("Failed to get transaction blob from db");
880 // ignore error
881 }
882 }
883 }
884 return true;
885 }, false);
886 return true;
887 }
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME
unsigned int uint32_t
Definition stdint.h:126

◆ get_transaction()

bool cryptonote::tx_memory_pool::get_transaction ( const crypto::hash & h,
cryptonote::blobdata & txblob ) const

get a specific transaction from the pool

Parameters
hthe hash of the transaction to get
txreturn-by-reference the transaction blob requested
Returns
true if the transaction is found, otherwise false

Definition at line 1185 of file tx_pool.cpp.

1186 {
1187 CRITICAL_REGION_LOCAL(m_transactions_lock);
1188 CRITICAL_REGION_LOCAL1(m_blockchain);
1189 try
1190 {
1191 return m_blockchain.get_txpool_tx_blob(id, txblob);
1192 }
1193 catch (const std::exception &e)
1194 {
1195 return false;
1196 }
1197 }
Here is the caller graph for this function:

◆ get_transaction_backlog()

void cryptonote::tx_memory_pool::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

Parameters
txsreturn-by-reference that data
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 953 of file tx_pool.cpp.

954 {
955 CRITICAL_REGION_LOCAL(m_transactions_lock);
956 CRITICAL_REGION_LOCAL1(m_blockchain);
957 const uint64_t now = time(NULL);
958 backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
959 m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
960 backlog.push_back({meta.weight, meta.fee, meta.receive_time - now});
961 return true;
962 }, false, include_unrelayed_txes);
963 }

◆ get_transaction_hashes()

void cryptonote::tx_memory_pool::get_transaction_hashes ( std::vector< crypto::hash > & txs,
bool include_unrelayed_txes = true ) const

get a list of all transaction hashes in the pool

Parameters
txsreturn-by-reference the list of transactions
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 942 of file tx_pool.cpp.

943 {
944 CRITICAL_REGION_LOCAL(m_transactions_lock);
945 CRITICAL_REGION_LOCAL1(m_blockchain);
946 txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
947 m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
948 txs.push_back(txid);
949 return true;
950 }, false, include_unrelayed_txes);
951 }

◆ get_transaction_stats()

void cryptonote::tx_memory_pool::get_transaction_stats ( struct txpool_stats & stats,
bool include_unrelayed_txes = true ) const

get a summary statistics of all transaction hashes in the pool

Parameters
statsreturn-by-reference the pool statistics
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 965 of file tx_pool.cpp.

966 {
967 CRITICAL_REGION_LOCAL(m_transactions_lock);
968 CRITICAL_REGION_LOCAL1(m_blockchain);
969 const uint64_t now = time(NULL);
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;
973 weights.reserve(stats.txs_total);
974 m_blockchain.for_all_txpool_txes([&stats, &weights, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
975 weights.push_back(meta.weight);
976 stats.bytes_total += meta.weight;
977 if (!stats.bytes_min || meta.weight < stats.bytes_min)
978 stats.bytes_min = meta.weight;
979 if (meta.weight > stats.bytes_max)
980 stats.bytes_max = meta.weight;
981 if (!meta.relayed)
982 stats.num_not_relayed++;
983 stats.fee_total += meta.fee;
984 if (!stats.oldest || meta.receive_time < stats.oldest)
985 stats.oldest = meta.receive_time;
986 if (meta.receive_time < now - 600)
987 stats.num_10m++;
988 if (meta.last_failed_height)
989 stats.num_failing++;
990 uint64_t age = now - meta.receive_time + (now == meta.receive_time);
991 agebytes[age].txs++;
992 agebytes[age].bytes += meta.weight;
993 if (meta.double_spend_seen)
994 ++stats.num_double_spends;
995 if(meta.utxo_nonexistent_seen)
996 ++stats.num_nonexistent_utxos;
997 return true;
998 }, false, include_unrelayed_txes);
999 stats.bytes_med = epee::misc_utils::median(weights);
1000 if (stats.txs_total > 1)
1001 {
1002 /* looking for 98th percentile */
1003 size_t end = stats.txs_total * 0.02;
1004 uint64_t delta, factor;
1005 std::map<uint64_t, txpool_histo>::iterator it, i2;
1006 if (end)
1007 {
1008 /* If enough txs, spread the first 98% of results across
1009 * the first 9 bins, drop final 2% in last bin.
1010 */
1011 it=agebytes.end();
1012 for (size_t n=0; n <= end; n++, it--);
1013 stats.histo_98pc = it->first;
1014 factor = 9;
1015 delta = it->first;
1016 stats.histo.resize(10);
1017 } else
1018 {
1019 /* If not enough txs, don't reserve the last slot;
1020 * spread evenly across all 10 bins.
1021 */
1022 stats.histo_98pc = 0;
1023 it = agebytes.end();
1024 factor = stats.txs_total > 9 ? 10 : stats.txs_total;
1025 delta = now - stats.oldest;
1026 stats.histo.resize(factor);
1027 }
1028 if (!delta)
1029 delta = 1;
1030 for (i2 = agebytes.begin(); i2 != it; i2++)
1031 {
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;
1035 }
1036 for (; i2 != agebytes.end(); i2++)
1037 {
1038 stats.histo[factor].txs += i2->second.txs;
1039 stats.histo[factor].bytes += i2->second.bytes;
1040 }
1041 }
1042 }
type_vec_type median(std::vector< type_vec_type > &v)
Here is the call graph for this function:

◆ get_transactions()

void cryptonote::tx_memory_pool::get_transactions ( std::vector< transaction > & txs,
bool include_unrelayed_txes = true ) const

get a list of all transactions in the pool

Parameters
txsreturn-by-reference the list of transactions
include_unrelayed_txesinclude unrelayed txes in the result

Definition at line 923 of file tx_pool.cpp.

924 {
925 CRITICAL_REGION_LOCAL(m_transactions_lock);
926 CRITICAL_REGION_LOCAL1(m_blockchain);
927 txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
928 m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
929 transaction tx;
931 {
932 MERROR("Failed to parse tx from txpool");
933 // continue
934 return true;
935 }
936 tx.set_hash(txid);
937 txs.push_back(std::move(tx));
938 return true;
939 }, true, include_unrelayed_txes);
940 }
Here is the call graph for this function:

◆ get_transactions_and_spent_keys_info()

bool cryptonote::tx_memory_pool::get_transactions_and_spent_keys_info ( std::vector< tx_info > & tx_infos,
std::vector< spent_key_image_info > & key_image_infos,
bool include_sensitive_data = true ) const

get information about all transactions and key images in the pool

see documentation on tx_info and spent_key_image_info for more details

Parameters
tx_infosreturn-by-reference the transactions' information
key_image_infosreturn-by-reference the spent key images' information
include_sensitive_datainclude unrelayed txes and fields that are sensitive to the node privacy
Returns
true

Definition at line 1045 of file tx_pool.cpp.

1046 {
1047 CRITICAL_REGION_LOCAL(m_transactions_lock);
1048 CRITICAL_REGION_LOCAL1(m_blockchain);
1049 tx_infos.reserve(m_blockchain.get_txpool_tx_count());
1050 key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
1051 m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos, include_sensitive_data](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
1052 tx_info txi;
1053 txi.id_hash = epee::string_tools::pod_to_hex(txid);
1054 txi.tx_blob = *bd;
1055 transaction tx;
1056 if (!parse_and_validate_tx_from_blob(*bd, tx))
1057 {
1058 MERROR("Failed to parse tx from txpool");
1059 // continue
1060 return true;
1061 }
1062 tx.set_hash(txid);
1063 txi.tx_json = obj_to_json_str(tx);
1064 txi.blob_size = bd->size();
1065 txi.weight = meta.weight;
1066 txi.fee = meta.fee;
1067 txi.kept_by_block = meta.kept_by_block;
1068 txi.max_used_block_height = meta.max_used_block_height;
1069 txi.max_used_block_id_hash = epee::string_tools::pod_to_hex(meta.max_used_block_id);
1070 txi.last_failed_height = meta.last_failed_height;
1071 txi.last_failed_id_hash = epee::string_tools::pod_to_hex(meta.last_failed_id);
1072 // In restricted mode we do not include this data:
1073 txi.receive_time = include_sensitive_data ? meta.receive_time : 0;
1074 txi.relayed = meta.relayed;
1075 // In restricted mode we do not include this data:
1076 txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
1077 txi.do_not_relay = meta.do_not_relay;
1078 txi.double_spend_seen = meta.double_spend_seen;
1079 txi.nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
1080
1081 tx_infos.push_back(std::move(txi));
1082 return true;
1083 }, true, include_sensitive_data);
1084
1085 txpool_tx_meta_t meta;
1086 for (const key_images_container::value_type& kee : m_spent_key_images) {
1087 const crypto::key_image& k_image = kee.first;
1088 const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
1089 spent_key_image_info ki;
1090 ki.id_hash = epee::string_tools::pod_to_hex(k_image);
1091 for (const crypto::hash& tx_id_hash : kei_image_set)
1092 {
1093 if (!include_sensitive_data)
1094 {
1095 try
1096 {
1097 if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
1098 {
1099 MERROR("Failed to get tx meta from txpool");
1100 return false;
1101 }
1102 if (!meta.relayed)
1103 // Do not include that transaction if in restricted mode and it's not relayed
1104 continue;
1105 }
1106 catch (const std::exception &e)
1107 {
1108 MERROR("Failed to get tx meta from txpool: " << e.what());
1109 return false;
1110 }
1111 }
1112 ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
1113 }
1114 // Only return key images for which we have at least one tx that we can show for them
1115 if (!ki.txs_hashes.empty())
1116 key_image_infos.push_back(ki);
1117 }
1118 return true;
1119 }
std::string obj_to_json_str(T &obj)
Here is the call graph for this function:

◆ get_transactions_count()

size_t cryptonote::tx_memory_pool::get_transactions_count ( bool include_unrelayed_txes = true) const

get the total number of transactions in the pool

Returns
the number of transactions in the pool

Definition at line 916 of file tx_pool.cpp.

917 {
918 CRITICAL_REGION_LOCAL(m_transactions_lock);
919 CRITICAL_REGION_LOCAL1(m_blockchain);
920 return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
921 }

◆ get_txpool_weight()

size_t cryptonote::tx_memory_pool::get_txpool_weight ( ) const

get the cumulative txpool weight in bytes

Returns
the cumulative txpool weight in bytes

Definition at line 554 of file tx_pool.cpp.

555 {
556 CRITICAL_REGION_LOCAL(m_transactions_lock);
557 return m_txpool_weight;
558 }

◆ have_tx()

bool cryptonote::tx_memory_pool::have_tx ( const crypto::hash & id) const

checks if the pool has a transaction with the given hash

Parameters
idthe hash to look for
Returns
true if the transaction is in the pool, otherwise false

Definition at line 1215 of file tx_pool.cpp.

1216 {
1217 CRITICAL_REGION_LOCAL(m_transactions_lock);
1218 CRITICAL_REGION_LOCAL1(m_blockchain);
1219 return m_blockchain.get_db().txpool_has_tx(id);
1220 }

◆ init()

bool cryptonote::tx_memory_pool::init ( size_t max_txpool_weight = 0)

loads pool state (if any) from disk, and initializes pool

Parameters
max_txpool_weightthe max weight in bytes
Returns
true

Definition at line 1750 of file tx_pool.cpp.

1751 {
1752 CRITICAL_REGION_LOCAL(m_transactions_lock);
1753 CRITICAL_REGION_LOCAL1(m_blockchain);
1754
1755 m_txpool_max_weight = max_txpool_weight ? max_txpool_weight : DEFAULT_TXPOOL_MAX_WEIGHT;
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;
1761
1762 // first add the not kept by block, then the kept by block,
1763 // to avoid rejection due to key image collision
1764 for (int pass = 0; pass < 2; ++pass)
1765 {
1766 const bool kept = pass == 1;
1767 bool r = m_blockchain.for_all_txpool_txes([this, &remove, kept](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) {
1768 if (!!kept != !!meta.kept_by_block)
1769 return true;
1770 cryptonote::transaction_prefix tx;
1772 {
1773 MWARNING("Failed to parse tx from txpool, removing");
1774 remove.push_back(txid);
1775 return true;
1776 }
1777 if (tx.version <= 2 && !insert_key_images(tx, txid, meta.kept_by_block))
1778 {
1779 MFATAL("Failed to insert key images from txpool tx");
1780 return false;
1781 }
1782 if (tx.version >= 3 && !insert_utxos(tx, txid, meta.kept_by_block))
1783 {
1784 MFATAL("Failed to insert utxos from txpool tx");
1785 return false;
1786 }
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;
1789 return true;
1790 }, true);
1791 if (!r)
1792 return false;
1793 }
1794 if (!remove.empty())
1795 {
1796 LockedTXN lock(m_blockchain);
1797 for (const auto &txid: remove)
1798 {
1799 try
1800 {
1801 m_blockchain.remove_txpool_tx(txid);
1802 }
1803 catch (const std::exception &e)
1804 {
1805 MWARNING("Failed to remove corrupt transaction: " << txid);
1806 // ignore error
1807 }
1808 }
1809 lock.commit();
1810 }
1811
1812 m_cookie = 0;
1813
1814 // Ignore deserialization error
1815 return true;
1816 }
#define MFATAL(x)
Definition misc_log_ex.h:72
#define MWARNING(x)
Definition misc_log_ex.h:74
bool parse_and_validate_tx_prefix_from_blob(const blobdata &tx_blob, transaction_prefix &tx)
Here is the call graph for this function:

◆ lock()

void cryptonote::tx_memory_pool::lock ( ) const

locks the transaction pool

Definition at line 1274 of file tx_pool.cpp.

1275 {
1276 m_transactions_lock.lock();
1277 }
Here is the caller graph for this function:

◆ on_blockchain_dec()

bool cryptonote::tx_memory_pool::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

Currently does nothing

Parameters
new_block_heightthe height of the blockchain after the change
top_block_idthe hash of the new top block
Returns
true

Definition at line 1207 of file tx_pool.cpp.

1208 {
1209 CRITICAL_REGION_LOCAL(m_transactions_lock);
1210 m_input_cache.clear();
1211 m_parsed_tx_cache.clear();
1212 return true;
1213 }

◆ on_blockchain_inc()

bool cryptonote::tx_memory_pool::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

Currently does nothing

Parameters
new_block_heightthe height of the blockchain after the change
top_block_idthe hash of the new top block
Returns
true

Definition at line 1199 of file tx_pool.cpp.

1200 {
1201 CRITICAL_REGION_LOCAL(m_transactions_lock);
1202 m_input_cache.clear();
1203 m_parsed_tx_cache.clear();
1204 return true;
1205 }

◆ on_idle()

void cryptonote::tx_memory_pool::on_idle ( )

action to take periodically

Currently checks transaction pool for stale ("stuck") transactions

Definition at line 777 of file tx_pool.cpp.

778 {
779 m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
780 }

◆ print_pool()

std::string cryptonote::tx_memory_pool::print_pool ( bool short_format) const

get a string containing human-readable pool information

Parameters
short_formatwhether to use a shortened format for the info
Returns
the string

Definition at line 1521 of file tx_pool.cpp.

1522 {
1523 std::stringstream ss;
1524 CRITICAL_REGION_LOCAL(m_transactions_lock);
1525 CRITICAL_REGION_LOCAL1(m_blockchain);
1526 m_blockchain.for_all_txpool_txes([&ss, short_format](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *txblob) {
1527 ss << "id: " << txid << std::endl;
1528 if (!short_format) {
1529 cryptonote::transaction tx;
1530 if (!parse_and_validate_tx_from_blob(*txblob, tx))
1531 {
1532 MERROR("Failed to parse tx from txpool");
1533 return true; // continue
1534 }
1535 ss << obj_to_json_str(tx) << std::endl;
1536 }
1537 ss << "blob_size: " << (short_format ? "-" : std::to_string(txblob->size())) << std::endl
1538 << "weight: " << meta.weight << std::endl
1539 << "fee: " << print_etn(meta.fee) << std::endl
1540 << "kept_by_block: " << (meta.kept_by_block ? 'T' : 'F') << std::endl
1541 << "double_spend_seen: " << (meta.double_spend_seen ? 'T' : 'F') << std::endl
1542 << "nonexistent_utxo_seen: " << (meta.utxo_nonexistent_seen ? 'T' : 'F') << std::endl
1543 << "max_used_block_height: " << meta.max_used_block_height << std::endl
1544 << "max_used_block_id: " << meta.max_used_block_id << std::endl
1545 << "last_failed_height: " << meta.last_failed_height << std::endl
1546 << "last_failed_id: " << meta.last_failed_id << std::endl;
1547 return true;
1548 }, !short_format);
1549
1550 return ss.str();
1551 }
Here is the call graph for this function:

◆ set_relayed()

void cryptonote::tx_memory_pool::set_relayed ( const std::vector< std::pair< crypto::hash, cryptonote::blobdata > > & txs)

tell the pool that certain transactions were just relayed

Parameters
txsthe list of transactions (and their hashes)

Definition at line 889 of file tx_pool.cpp.

890 {
891 CRITICAL_REGION_LOCAL(m_transactions_lock);
892 CRITICAL_REGION_LOCAL1(m_blockchain);
893 const time_t now = time(NULL);
894 LockedTXN lock(m_blockchain);
895 for (auto it = txs.begin(); it != txs.end(); ++it)
896 {
897 try
898 {
899 txpool_tx_meta_t meta;
900 if (m_blockchain.get_txpool_tx_meta(it->first, meta))
901 {
902 meta.relayed = true;
903 meta.last_relayed_time = now;
904 m_blockchain.update_txpool_tx(it->first, meta);
905 }
906 }
907 catch (const std::exception &e)
908 {
909 MERROR("Failed to update txpool transaction metadata: " << e.what());
910 // continue
911 }
912 }
913 lock.commit();
914 }
Here is the call graph for this function:

◆ set_txpool_max_weight()

void cryptonote::tx_memory_pool::set_txpool_max_weight ( size_t bytes)

set the max cumulative txpool weight in bytes

Parameters
bytesthe max cumulative txpool weight in bytes

Definition at line 560 of file tx_pool.cpp.

561 {
562 CRITICAL_REGION_LOCAL(m_transactions_lock);
563 m_txpool_max_weight = bytes;
564 }

◆ take_tx()

bool cryptonote::tx_memory_pool::take_tx ( const crypto::hash & id,
transaction & tx,
cryptonote::blobdata & txblob,
size_t & tx_weight,
uint64_t & fee,
bool & relayed,
bool & do_not_relay,
bool & double_spend_seen,
bool & nonexistent_utxo_seen )

takes a transaction with the given hash from the pool

Parameters
idthe hash of the transaction
txreturn-by-reference the transaction taken
txblobreturn-by-reference the transaction as a blob
tx_weightreturn-by-reference the transaction's weight
feethe transaction fee
relayedreturn-by-reference was transaction relayed to us by the network?
do_not_relayreturn-by-reference is transaction not to be relayed to the network?
double_spend_seenreturn-by-reference was a double spend seen for that transaction?
nonexistent_utxo_seenreturn-by-reference was a nonexistent utxo seen for that transaction?
Returns
true unless the transaction cannot be found in the pool

Definition at line 721 of file tx_pool.cpp.

722 {
723 CRITICAL_REGION_LOCAL(m_transactions_lock);
724 CRITICAL_REGION_LOCAL1(m_blockchain);
725
726 auto sorted_it = find_tx_in_sorted_container(id);
727
728 try
729 {
730 LockedTXN lock(m_blockchain);
731 txpool_tx_meta_t meta;
732 if (!m_blockchain.get_txpool_tx_meta(id, meta))
733 {
734 MERROR("Failed to find tx in txpool");
735 return false;
736 }
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())
740 {
741 tx = ci->second;
742 }
743 else if (!parse_and_validate_tx_from_blob(txblob, tx))
744 {
745 MERROR("Failed to parse tx from txpool");
746 return false;
747 }
748 else
749 {
750 tx.set_hash(id);
751 }
752 tx_weight = meta.weight;
753 fee = meta.fee;
754 relayed = meta.relayed;
755 do_not_relay = meta.do_not_relay;
756 double_spend_seen = meta.double_spend_seen;
757 nonexistent_utxo_seen = meta.utxo_nonexistent_seen;
758
759 // remove first, in case this throws, so key images aren't removed
760 m_blockchain.remove_txpool_tx(id);
761 m_txpool_weight -= tx_weight;
762 remove_transaction_keyimages(tx, id);
763 lock.commit();
764 }
765 catch (const std::exception &e)
766 {
767 MERROR("Failed to remove tx from txpool: " << e.what());
768 return false;
769 }
770
771 if (sorted_it != m_txs_by_fee_and_receive_time.end())
772 m_txs_by_fee_and_receive_time.erase(sorted_it);
773 ++m_cookie;
774 return true;
775 }
Here is the call graph for this function:

◆ unlock()

void cryptonote::tx_memory_pool::unlock ( ) const

unlocks the transaction pool

Definition at line 1279 of file tx_pool.cpp.

1280 {
1281 m_transactions_lock.unlock();
1282 }

◆ utxo_spent_in_pool()

bool cryptonote::tx_memory_pool::utxo_spent_in_pool ( const txin_to_key_public & in) const

get a summary statistics of all transaction hashes in the pool

Parameters
ininput to check the pool spent status of

Definition at line 1239 of file tx_pool.cpp.

1239 {
1240 CRITICAL_REGION_LOCAL(m_transactions_lock);
1241 CRITICAL_REGION_LOCAL1(m_blockchain);
1242 return have_tx_utxo_as_spent(in);
1243 }

◆ validate()

size_t cryptonote::tx_memory_pool::validate ( uint8_t version)

remove transactions from the pool which are no longer valid

With new versions of the currency, what conditions render a transaction invalid may change. This function clears those which were received before a version change and no longer conform to requirements.

Parameters
versionthe version the transactions must conform to
Returns
the number of transactions removed

Definition at line 1686 of file tx_pool.cpp.

1687 {
1688 CRITICAL_REGION_LOCAL(m_transactions_lock);
1689 CRITICAL_REGION_LOCAL1(m_blockchain);
1690 size_t tx_weight_limit = get_transaction_weight_limit(version);
1691 std::unordered_set<crypto::hash> remove;
1692
1693 m_txpool_weight = 0;
1694 m_blockchain.for_all_txpool_txes([this, &remove, tx_weight_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
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);
1699 }
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);
1703 }
1704 return true;
1705 }, false);
1706
1707 size_t n_removed = 0;
1708 if (!remove.empty())
1709 {
1710 LockedTXN lock(m_blockchain);
1711 for (const crypto::hash &txid: remove)
1712 {
1713 try
1714 {
1715 cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
1716 cryptonote::transaction tx;
1717 if (!parse_and_validate_tx_from_blob(txblob, tx))
1718 {
1719 MERROR("Failed to parse tx from txpool");
1720 continue;
1721 }
1722 // remove tx from db first
1723 m_blockchain.remove_txpool_tx(txid);
1724 m_txpool_weight -= get_transaction_weight(tx, txblob.size());
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())
1728 {
1729 LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
1730 }
1731 else
1732 {
1733 m_txs_by_fee_and_receive_time.erase(sorted_it);
1734 }
1735 ++n_removed;
1736 }
1737 catch (const std::exception &e)
1738 {
1739 MERROR("Failed to remove invalid tx from pool");
1740 // continue
1741 }
1742 }
1743 lock.commit();
1744 }
1745 if (n_removed > 0)
1746 ++m_cookie;
1747 return n_removed;
1748 }
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
Here is the call graph for this function:

The documentation for this class was generated from the following files:
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/cryptonote_core/tx_pool.h
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/cryptonote_core/tx_pool.cpp