Merge pull request #197 from Doy-lee/BlockchainPopBlocksCommand

Blockchain pop_blocks command
This commit is contained in:
jcktm 2018-09-11 18:07:55 +10:00 committed by GitHub
commit 0796630ffa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 155 additions and 0 deletions

View file

@ -1114,6 +1114,18 @@ namespace cryptonote
return result;
}
//-----------------------------------------------------------------------------------------------
void core::pop_blocks(size_t num_blocks_to_pop)
{
m_blockchain_storage.get_db().batch_start();
for (size_t i = 0; i < num_blocks_to_pop; i++)
{
block blk;
std::vector<transaction> txs;
m_blockchain_storage.get_db().pop_block(blk, txs);
}
m_blockchain_storage.get_db().batch_stop();
}
//-----------------------------------------------------------------------------------------------
bool core::handle_uptime_proof(uint64_t timestamp, const crypto::public_key& pubkey, const crypto::signature& sig)
{
return m_quorum_cop.handle_uptime_proof(timestamp, pubkey, sig);

View file

@ -843,6 +843,14 @@ namespace cryptonote
*/
uint64_t get_uptime_proof(const crypto::public_key &key) const;
/**
* @brief Pop 'n' block(s) from the chain
*
* @param num_blocks_to_pop The number of blocks to pop
*
*/
void pop_blocks(uint64_t num_blocks_to_pop);
private:
/**

View file

@ -729,4 +729,25 @@ bool t_command_parser_executor::version(const std::vector<std::string>& args)
return true;
}
bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args)
{
if (args.size() != 1)
return false;
size_t num_blocks_to_pop;
if(!epee::string_tools::get_xtype_from_string(num_blocks_to_pop, args[0]))
{
std::cout << "wrong starter block index parameter" << std::endl;
return false;
}
bool result = m_executor.pop_blocks(num_blocks_to_pop);
if (result)
{
raise(SIGTERM);
}
return result;
}
} // namespace daemonize

View file

@ -152,6 +152,8 @@ public:
bool sync_info(const std::vector<std::string>& args);
bool version(const std::vector<std::string>& args);
bool pop_blocks(const std::vector<std::string>& args);
};
} // namespace daemonize

View file

@ -322,6 +322,12 @@ t_command_server::t_command_server(
, std::bind(&t_command_parser_executor::version, &m_parser, p::_1)
, "Print version information."
);
m_command_lookup.set_handler(
"pop_blocks"
, std::bind(&t_command_parser_executor::pop_blocks, &m_parser, p::_1)
, "pop_blocks <num_blocks_to_pop>"
, "Remove a number of blocks from the top of the chain"
);
}
bool t_command_server::process_command_str(const std::string& cmd)

View file

@ -2666,4 +2666,64 @@ bool t_rpc_command_executor::prepare_registration()
return true;
}
bool t_rpc_command_executor::pop_blocks(size_t num_blocks_to_pop)
{
if (m_is_rpc)
{
std::cout << "Cannot pop_blocks over RPC as this will shut down your daemon." << std::endl;
return true;
}
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
// TODO(loki): Ideally without having to shutdown the daemon would be nice. But there's state
// left over in terms of if you do this while syncing it will keep requesting the wrong height,
// and the detached hooks we need to deal with.
std::string confirmation;
confirmation.reserve(8);
std::cout << "This is an advanced command for modifying your blockchain.\n"
"This command will only work in offline mode.\n"
"Executing this command will shut down your daemon. Please restart it afterwards.\n"
"Are you sure you wish to continue? (Y/Yes/N/No): ";
std::cin >> confirmation;
if(!command_line::is_yes(confirmation))
{
std::cout << "Aborted." << std::endl;
return true;
}
// Get Height
cryptonote::COMMAND_RPC_GET_HEIGHT::request height_req;
cryptonote::COMMAND_RPC_GET_HEIGHT::response height_res;
std::string fail_message = "Unsuccessful";
if (!m_rpc_server->on_get_height(height_req, height_res) || height_res.status != CORE_RPC_STATUS_OK)
{
tools::fail_msg_writer() << make_error(fail_message, height_res.status);
return true;
}
if (num_blocks_to_pop >= height_res.height)
{
tools::fail_msg_writer() << "Requested to pop too many blocks. Requested: " << num_blocks_to_pop << ", current height: " << height_res.height;
return true;
}
// Pop Block
cryptonote::COMMAND_RPC_POP_BLOCKS::request req = {};
cryptonote::COMMAND_RPC_POP_BLOCKS::response res = {};
req.num_blocks_to_pop = num_blocks_to_pop;
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() << "Popped: " << num_blocks_to_pop << " blocks";
return true;
}
}// namespace daemonize

View file

@ -167,6 +167,8 @@ public:
bool prepare_registration();
bool print_sn(const std::vector<std::string> &args);
bool pop_blocks(size_t num_blocks_to_pop);
};
} // namespace daemonize

View file

@ -2004,6 +2004,30 @@ namespace cryptonote
return r;
}
//------------------------------------------------------------------------------------------------------------------------------
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);
// TODO(loki): It'd be nice not to need to be offline, but it makes
// implementation much easier to not handle any race conditions right now.
// And this is a really handy feature for debugging chains.
// TODO(loki): This doesn't activate service node lists rollbacks. But will
// trigger a rescan from scratch. Again simpler to not handle right now.
// Putting the Blockchaindetached hook in the pop blocks call may work, but
// haven't investigated the repercussions of that.
if (!m_core.offline())
{
res.status = "Daemon must be running in offline mode to pop blocks.";
return false;
}
m_core.pop_blocks(req.num_blocks_to_pop);
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_service_node_key(const COMMAND_RPC_GET_SERVICE_NODE_KEY::request& req, COMMAND_RPC_GET_SERVICE_NODE_KEY::response& res, epee::json_rpc::error &error_resp)
{
PERF_TIMER(on_get_service_node_key);

View file

@ -197,6 +197,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_quorum_state(const COMMAND_RPC_GET_QUORUM_STATE::request& req, COMMAND_RPC_GET_QUORUM_STATE::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);

View file

@ -2435,4 +2435,23 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_POP_BLOCKS
{
struct request
{
size_t num_blocks_to_pop;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(num_blocks_to_pop)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
};
}