Skip to content

Commit

Permalink
src: fast pop_blocks and flush_txpool
Browse files Browse the repository at this point in the history
  • Loading branch information
0xFFFC0000 committed Sep 20, 2024
1 parent 4cd340d commit 8315f0f
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 39 deletions.
4 changes: 3 additions & 1 deletion external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
# others.

find_package(Miniupnpc REQUIRED)

if(NOT MSVC)
add_compile_options(-D_GNU_SOURCE)
endif()
message(STATUS "Using in-tree miniupnpc")
set(UPNPC_NO_INSTALL TRUE CACHE BOOL "Disable miniupnp installation" FORCE)
add_subdirectory(miniupnp/miniupnpc)
Expand Down
35 changes: 26 additions & 9 deletions src/cryptonote_core/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ bool Blockchain::deinit()
//------------------------------------------------------------------
// This function removes blocks from the top of blockchain.
// It starts a batch and calls private method pop_block_from_blockchain().
void Blockchain::pop_blocks(uint64_t nblocks)
void Blockchain::pop_blocks(uint64_t nblocks, bool is_fast_mode)
{
uint64_t i = 0;
CRITICAL_REGION_LOCAL(m_tx_pool);
Expand All @@ -564,7 +564,7 @@ void Blockchain::pop_blocks(uint64_t nblocks)
nblocks = std::min(nblocks, blockchain_height - 1);
while (i < nblocks)
{
pop_block_from_blockchain();
pop_block_from_blockchain(is_fast_mode);
++i;
}
}
Expand All @@ -591,7 +591,7 @@ void Blockchain::pop_blocks(uint64_t nblocks)
// This function tells BlockchainDB to remove the top block from the
// blockchain and then returns all transactions (except the miner tx, of course)
// from it to the tx_pool
block Blockchain::pop_block_from_blockchain()
block Blockchain::pop_block_from_blockchain(bool is_fast_mode)
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
Expand All @@ -608,6 +608,10 @@ block Blockchain::pop_block_from_blockchain()
try
{
m_db->pop_block(popped_block, popped_txs);
if(is_fast_mode)
{
popped_txs.clear();
}
}
// anything that could cause this to throw is likely catastrophic,
// so we re-throw
Expand Down Expand Up @@ -4030,13 +4034,26 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
bool res = true;
for (const auto &txid: txids)
{
cryptonote::transaction tx;
cryptonote::blobdata txblob;
size_t tx_weight;
uint64_t fee;
bool relayed, do_not_relay, double_spend_seen, pruned;
MINFO("Removing txid " << txid << " from the pool");
if(m_tx_pool.have_tx(txid, relay_category::all) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, pruned))
if(m_tx_pool.have_tx(txid, relay_category::all) && !m_tx_pool.remove_tx(txid))
{
MERROR("Failed to remove txid " << txid << " from the pool");
res = false;
}
}
return res;
}
//------------------------------------------------------------------
bool Blockchain::flush_txes_from_pool(const std::vector<transaction> &txs)
{
CRITICAL_REGION_LOCAL(m_tx_pool);

bool res = true;
for (const auto &tx: txs)
{
crypto::hash txid = get_transaction_hash(tx);
MINFO("Removing txid " << txid << " from the pool");
if(m_tx_pool.have_tx(txid, relay_category::all) && !m_tx_pool.remove_tx(tx,txid))
{
MERROR("Failed to remove txid " << txid << " from the pool");
res = false;
Expand Down
18 changes: 13 additions & 5 deletions src/cryptonote_core/blockchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -948,13 +948,21 @@ namespace cryptonote
uint64_t get_difficulty_target() const;

/**
* @brief remove transactions from the transaction pool (if present)
* @brief remove provided transactions from the transaction pool (if present)
*
* @param txids a list of hashes of transactions to be removed
*
* @return false if any removals fail, otherwise true
*/
bool flush_txes_from_pool(const std::vector<crypto::hash> &txids);
/**
* @brief remove provided transactions from the transaction pool (if present)
*
* @param txs a list of transactions to be removed
*
* @return false if any removals fail, otherwise true
*/
bool flush_txes_from_pool(const std::vector<transaction> &txs);

/**
* @brief return a histogram of outputs on the blockchain
Expand Down Expand Up @@ -1093,10 +1101,10 @@ namespace cryptonote

/**
* @brief removes blocks from the top of the blockchain
*
* @param is_fast_mode if fast mode is enabled doesnt add trx to pool
* @param nblocks number of blocks to be removed
*/
void pop_blocks(uint64_t nblocks);
void pop_blocks(uint64_t nblocks, bool is_fast_mode = false);

/**
* @brief checks whether a given block height is included in the precompiled block hash area
Expand Down Expand Up @@ -1331,10 +1339,10 @@ namespace cryptonote

/**
* @brief removes the most recent block from the blockchain
*
* @param is_fast_mode if fast mode is enabled doesnt add trx to pool
* @return the block removed
*/
block pop_block_from_blockchain();
block pop_block_from_blockchain(bool is_fast_mode = false);

/**
* @brief validate and add a new block to the end of the blockchain
Expand Down
75 changes: 75 additions & 0 deletions src/cryptonote_core/tx_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,81 @@ namespace cryptonote
++m_cookie;
return true;
}
//-----------------------------------------------------------------
bool tx_memory_pool::remove_tx(const transaction &tx,const crypto::hash &id){
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
bool sensitive = false;
try
{
LockedTXN lock(m_blockchain.get_db());
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(id, meta))
{
MERROR("Failed to find tx_meta in txpool");
return false;
}
sensitive = !meta.matches(relay_category::broadcasted);
// remove first, in case this throws, so key images aren't removed
m_blockchain.remove_txpool_tx(id);
reduce_txpool_weight(meta.weight);
remove_transaction_keyimages(tx, id);
lock.commit();
}
catch (const std::exception &e)
{
MERROR("Failed to remove tx from txpool: " << e.what());
return false;
}

remove_tx_from_transient_lists(find_tx_in_sorted_container(id), id, sensitive);
++m_cookie;
return true;
}
//-----------------------------------------------------------------
bool tx_memory_pool::remove_tx(const crypto::hash &id){
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
transaction tx;
cryptonote::blobdata txblob;
bool sensitive = false;
try
{
LockedTXN lock(m_blockchain.get_db());
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(id, meta))
{
MERROR("Failed to find tx_meta in txpool");
return false;
}
txblob = m_blockchain.get_txpool_tx_blob(id, relay_category::all);
auto ci = m_parsed_tx_cache.find(id);
if (ci != m_parsed_tx_cache.end())
{
tx = ci->second;
}
else if (!(meta.pruned ? parse_and_validate_tx_base_from_blob(txblob, tx) : parse_and_validate_tx_prefix_from_blob(txblob, tx)))
{
MERROR("Failed to parse tx from txpool");
return false;
}
sensitive = !meta.matches(relay_category::broadcasted);
// remove first, in case this throws, so key images aren't removed
m_blockchain.remove_txpool_tx(id);
reduce_txpool_weight(meta.weight);
remove_transaction_keyimages(tx, id);
lock.commit();
}
catch (const std::exception &e)
{
MERROR("Failed to remove tx from txpool: " << e.what());
return false;
}

remove_tx_from_transient_lists(find_tx_in_sorted_container(id), id, sensitive);
++m_cookie;
return true;
}
//---------------------------------------------------------------------------------
bool 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 &pruned)
{
Expand Down
17 changes: 16 additions & 1 deletion src/cryptonote_core/tx_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,22 @@ namespace cryptonote
* @return true unless the transaction cannot be found 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 &pruned);

/**
* @brief remove the transaction with the given hash from the pool
*
* @param id the hash of the transaction
*
* @return true if the trx was removed successfully
*/
bool remove_tx(const crypto::hash &id);
/**
* @brief remove the transaction with the given hash from the pool
*
* @param id the hash of the transaction
*
* @return true if the trx was removed successfully
*/
bool remove_tx(const transaction &tx,const crypto::hash &id);
/**
* @brief checks if the pool has a transaction with the given hash
*
Expand Down
9 changes: 5 additions & 4 deletions src/daemon/command_parser_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,21 +921,22 @@ bool t_command_parser_executor::sync_info(const std::vector<std::string>& args)

bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args)
{
if (args.size() != 1)
if (args.size() < 1 || args.size() > 2)
{
std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
std::cout << "Invalid syntax: One or two parameter expected. For more details, use the help command." << std::endl;
return true;
}

try
{
uint64_t nblocks = boost::lexical_cast<uint64_t>(args[0]);
std::string fast_mode_option = boost::lexical_cast<std::string>(args[1]);
if (nblocks < 1)
{
std::cout << "Invalid syntax: Number of blocks must be greater than 0. For more details, use the help command." << std::endl;
return true;
}
return m_executor.pop_blocks(nblocks);
return m_executor.pop_blocks(nblocks, fast_mode_option);
}
catch (const boost::bad_lexical_cast&)
{
Expand Down
3 changes: 2 additions & 1 deletion src/daemon/rpc_command_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2317,13 +2317,14 @@ bool t_rpc_command_executor::sync_info()
return true;
}

bool t_rpc_command_executor::pop_blocks(uint64_t num_blocks)
bool t_rpc_command_executor::pop_blocks(uint64_t num_blocks, std::string fast_mode_option)
{
cryptonote::COMMAND_RPC_POP_BLOCKS::request req;
cryptonote::COMMAND_RPC_POP_BLOCKS::response res;
std::string fail_message = "pop_blocks failed";

req.nblocks = num_blocks;
req.fast_mode_option = fast_mode_option;
if (m_is_rpc)
{
if (!m_rpc_client->rpc_request(req, res, "/pop_blocks", fail_message.c_str()))
Expand Down
2 changes: 1 addition & 1 deletion src/daemon/rpc_command_executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class t_rpc_command_executor final {

bool sync_info();

bool pop_blocks(uint64_t num_blocks);
bool pop_blocks(uint64_t num_blocks, std::string fast_mode_option);

bool prune_blockchain();

Expand Down
28 changes: 12 additions & 16 deletions src/rpc/core_rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2891,7 +2891,7 @@ namespace cryptonote
RPC_TRACKER(flush_txpool);

bool failed = false;
std::vector<crypto::hash> txids;

if (req.txids.empty())
{
std::vector<transaction> pool_txs;
Expand All @@ -2901,13 +2901,15 @@ namespace cryptonote
res.status = "Failed to get txpool contents";
return true;
}
for (const auto &tx: pool_txs)
if (!m_core.get_blockchain_storage().flush_txes_from_pool(pool_txs))
{
txids.push_back(cryptonote::get_transaction_hash(tx));
res.status = "Failed to remove one or more tx(es)";
return true;
}
}
else
{
std::vector<crypto::hash> txids;
for (const auto &str: req.txids)
{
crypto::hash txid;
Expand All @@ -2920,19 +2922,15 @@ namespace cryptonote
txids.push_back(txid);
}
}
if (!m_core.get_blockchain_storage().flush_txes_from_pool(txids))
{
res.status = "Failed to remove one or more tx(es)";
return true;
}
}
if (!m_core.get_blockchain_storage().flush_txes_from_pool(txids))
{
res.status = "Failed to remove one or more tx(es)";
return true;
}

if (failed)
{
if (txids.empty())
res.status = "Failed to parse txid";
else
res.status = "Failed to parse some of the txids";
res.status = "Failed to parse some or all of the txids";
return true;
}

Expand Down Expand Up @@ -3251,9 +3249,7 @@ namespace cryptonote
bool core_rpc_server::on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request& req, COMMAND_RPC_POP_BLOCKS::response& res, const connection_context *ctx)
{
RPC_TRACKER(pop_blocks);

m_core.get_blockchain_storage().pop_blocks(req.nblocks);

m_core.get_blockchain_storage().pop_blocks(req.nblocks, req.fast_mode_option == "fast");
res.height = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;

Expand Down
3 changes: 2 additions & 1 deletion src/rpc/core_rpc_server_commands_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2724,10 +2724,11 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
struct request_t: public rpc_request_base
{
uint64_t nblocks;

std::string fast_mode_option;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(nblocks)
KV_SERIALIZE_OPT(fast_mode_option,(std::string)"")
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
Expand Down

0 comments on commit 8315f0f

Please sign in to comment.