tx_pool: hold off parsing a tx blob till we actually need it

This commit is contained in:
moneromooo-monero 2018-06-01 21:50:46 +01:00
parent 8a7b3ff138
commit 2b0c632f32
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
2 changed files with 35 additions and 12 deletions

View file

@ -927,8 +927,26 @@ namespace cryptonote
m_transactions_lock.unlock();
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, transaction &tx) const
bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const cryptonote::blobdata &txblob, transaction &tx) const
{
struct transction_parser
{
transction_parser(const cryptonote::blobdata &txblob, transaction &tx): txblob(txblob), tx(tx), parsed(false) {}
cryptonote::transaction &operator()()
{
if (!parsed)
{
if (!parse_and_validate_tx_from_blob(txblob, tx))
throw std::runtime_error("failed to parse transaction blob");
parsed = true;
}
return tx;
}
const cryptonote::blobdata &txblob;
transaction &tx;
bool parsed;
} lazy_tx(txblob, tx);
//not the best implementation at this time, sorry :(
//check is ring_signature already checked ?
if(txd.max_used_block_id == null_hash)
@ -938,7 +956,7 @@ namespace cryptonote
return false;//we already sure that this tx is broken for this height
tx_verification_context tvc;
if(!m_blockchain.check_tx_inputs(tx, txd.max_used_block_height, txd.max_used_block_id, tvc))
if(!m_blockchain.check_tx_inputs(lazy_tx(), txd.max_used_block_height, txd.max_used_block_id, tvc))
{
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
@ -955,7 +973,7 @@ namespace cryptonote
return false;
//check ring signature again, it is possible (with very small chance) that this transaction become again valid
tx_verification_context tvc;
if(!m_blockchain.check_tx_inputs(tx, txd.max_used_block_height, txd.max_used_block_id, tvc))
if(!m_blockchain.check_tx_inputs(lazy_tx(), txd.max_used_block_height, txd.max_used_block_id, tvc))
{
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
@ -964,7 +982,7 @@ namespace cryptonote
}
}
//if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure
if(m_blockchain.have_tx_keyimges_as_spent(tx))
if(m_blockchain.have_tx_keyimges_as_spent(lazy_tx()))
{
txd.double_spend_seen = true;
return false;
@ -1140,18 +1158,21 @@ namespace cryptonote
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second);
cryptonote::transaction tx;
if (!parse_and_validate_tx_from_blob(txblob, tx))
{
MERROR("Failed to parse tx from txpool");
sorted_it++;
continue;
}
// Skip transactions that are not ready to be
// included into the blockchain or that are
// missing key images
const cryptonote::txpool_tx_meta_t original_meta = meta;
bool ready = is_transaction_ready_to_go(meta, tx);
bool ready = false;
try
{
ready = is_transaction_ready_to_go(meta, txblob, tx);
}
catch (const std::exception &e)
{
MERROR("Failed to check transaction readiness: " << e.what());
// continue, not fatal
}
if (memcmp(&original_meta, &meta, sizeof(meta)))
{
try

View file

@ -499,10 +499,12 @@ namespace cryptonote
* @brief check if a transaction is a valid candidate for inclusion in a block
*
* @param txd the transaction to check (and info about it)
* @param txblob the transaction blob to check
* @param tx the parsed transaction, if successful
*
* @return true if the transaction is good to go, otherwise false
*/
bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, transaction &tx) const;
bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const cryptonote::blobdata &txblob, transaction &tx) const;
/**
* @brief mark all transactions double spending the one passed