aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cryptonote_core/blockchain.cpp32
-rw-r--r--src/cryptonote_core/blockchain.h7
-rw-r--r--src/daemon/command_parser_executor.cpp25
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp6
-rw-r--r--src/daemon/rpc_command_executor.cpp27
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/rpc/core_rpc_server.cpp12
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h23
10 files changed, 138 insertions, 0 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index ebdb6ed79..1cc7d718c 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -576,6 +576,38 @@ bool Blockchain::deinit()
return true;
}
//------------------------------------------------------------------
+// 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)
+{
+ uint64_t i;
+ CRITICAL_REGION_LOCAL(m_tx_pool);
+ CRITICAL_REGION_LOCAL1(m_blockchain_lock);
+
+ while (!m_db->batch_start())
+ {
+ m_blockchain_lock.unlock();
+ m_tx_pool.unlock();
+ epee::misc_utils::sleep_no_w(1000);
+ m_tx_pool.lock();
+ m_blockchain_lock.lock();
+ }
+
+ try
+ {
+ for (i=0; i < nblocks; ++i)
+ {
+ pop_block_from_blockchain();
+ }
+ }
+ catch (const std::exception& e)
+ {
+ LOG_ERROR("Error when popping blocks, only " << i << " blocks are popped: " << e.what());
+ }
+
+ m_db->batch_stop();
+}
+//------------------------------------------------------------------
// 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
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index dfe833fb4..f1e366c9e 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -967,6 +967,13 @@ namespace cryptonote
*/
std::vector<time_t> get_last_block_timestamps(unsigned int blocks) const;
+ /**
+ * @brief removes blocks from the top of the blockchain
+ *
+ * @param nblocks number of blocks to be removed
+ */
+ void pop_blocks(uint64_t nblocks);
+
private:
// TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 1638cf505..853cde9c3 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -674,6 +674,31 @@ bool t_command_parser_executor::sync_info(const std::vector<std::string>& args)
return m_executor.sync_info();
}
+bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args)
+{
+ if (args.size() != 1)
+ {
+ std::cout << "Exactly one parameter is needed" << std::endl;
+ return false;
+ }
+
+ try
+ {
+ uint64_t nblocks = boost::lexical_cast<uint64_t>(args[0]);
+ if (nblocks < 1)
+ {
+ std::cout << "number of blocks must be greater than 0" << std::endl;
+ return false;
+ }
+ return m_executor.pop_blocks(nblocks);
+ }
+ catch (const boost::bad_lexical_cast&)
+ {
+ std::cout << "number of blocks must be a number greater than 0" << std::endl;
+ }
+ return false;
+}
+
bool t_command_parser_executor::version(const std::vector<std::string>& args)
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << std::endl;
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index a70070171..e2844e8b7 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -139,6 +139,8 @@ public:
bool sync_info(const std::vector<std::string>& args);
+ bool pop_blocks(const std::vector<std::string>& args);
+
bool version(const std::vector<std::string>& args);
};
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 35504f2c9..527ed2cf1 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -282,6 +282,12 @@ t_command_server::t_command_server(
, "Print information about the blockchain sync state."
);
m_command_lookup.set_handler(
+ "pop_blocks"
+ , std::bind(&t_command_parser_executor::pop_blocks, &m_parser, p::_1)
+ , "pop_blocks <nblocks>"
+ , "Remove blocks from end of blockchain"
+ );
+ m_command_lookup.set_handler(
"version"
, std::bind(&t_command_parser_executor::version, &m_parser, p::_1)
, "Print version information."
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 5ae9851a7..015e1e1f9 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -1967,4 +1967,31 @@ bool t_rpc_command_executor::sync_info()
return true;
}
+bool t_rpc_command_executor::pop_blocks(uint64_t num_blocks)
+{
+ 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;
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/pop_blocks", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_pop_blocks(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+ tools::success_msg_writer() << "new height: " << res.height;
+
+ return true;
+}
+
}// namespace daemonize
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 9e6010c5b..592584a5f 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -152,6 +152,8 @@ public:
bool relay_tx(const std::string &txid);
bool sync_info();
+
+ bool pop_blocks(uint64_t num_blocks);
};
} // namespace daemonize
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index cefba39f7..3851af3c8 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -2032,6 +2032,18 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request& req, COMMAND_RPC_POP_BLOCKS::response& res)
+ {
+ PERF_TIMER(on_pop_blocks);
+
+ m_core.get_blockchain_storage().pop_blocks(req.nblocks);
+
+ res.height = m_core.get_current_blockchain_height();
+ res.status = CORE_RPC_STATUS_OK;
+
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_relay_tx(const COMMAND_RPC_RELAY_TX::request& req, COMMAND_RPC_RELAY_TX::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_relay_tx);
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 6a616e2e0..081ccc25d 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -117,6 +117,7 @@ namespace cryptonote
MAP_URI_AUTO_JON2("/get_outs", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
MAP_URI_AUTO_JON2_IF("/update", on_update, COMMAND_RPC_UPDATE, !m_restricted)
MAP_URI_AUTO_BIN2("/get_output_distribution.bin", on_get_output_distribution_bin, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION)
+ MAP_URI_AUTO_JON2_IF("/pop_blocks", on_pop_blocks, COMMAND_RPC_POP_BLOCKS, !m_restricted)
BEGIN_JSON_RPC_MAP("/json_rpc")
MAP_JON_RPC("get_block_count", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT)
MAP_JON_RPC("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT)
@@ -188,6 +189,7 @@ namespace cryptonote
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res);
bool on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res);
bool on_get_output_distribution_bin(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res);
+ bool on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request& req, COMMAND_RPC_POP_BLOCKS::response& res);
//json_rpc
bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index d54bfbf8d..0a07930ec 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -2328,4 +2328,27 @@ namespace cryptonote
};
};
+ struct COMMAND_RPC_POP_BLOCKS
+ {
+ struct request
+ {
+ uint64_t nblocks;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(nblocks);
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+ uint64_t height;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(height)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
}