forked from lthn/blockchain
peer log downloading
This commit is contained in:
parent
d1d048f4b0
commit
f68a7cfa7a
6 changed files with 347 additions and 3 deletions
|
|
@ -526,4 +526,65 @@ std::string get_nix_version_display_string()
|
|||
#endif
|
||||
return std::error_code(code, std::system_category());
|
||||
}
|
||||
|
||||
#define REQUEST_LOG_CHUNK_SIZE_MAX (10 * 1024 * 1024)
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error)
|
||||
{
|
||||
if (size > REQUEST_LOG_CHUNK_SIZE_MAX)
|
||||
{
|
||||
error = std::string("size is exceeding the limit = ") + epee::string_tools::num_to_string_fast(REQUEST_LOG_CHUNK_SIZE_MAX);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
if (std::ifstream log{ log_filename, std::ifstream::ate | std::ifstream::binary })
|
||||
{
|
||||
uint64_t file_size = log.tellg();
|
||||
|
||||
if (offset >= file_size)
|
||||
{
|
||||
error = "offset is out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset + size > file_size)
|
||||
{
|
||||
error = "offset + size if out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
log.seekg(offset);
|
||||
output.resize(size);
|
||||
log.read(&output.front(), size);
|
||||
uint64_t read_bytes = log.gcount();
|
||||
if (read_bytes != size)
|
||||
{
|
||||
error = std::string("read bytes: ") + epee::string_tools::num_to_string_fast(read_bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::pack(output))
|
||||
{
|
||||
error = "zlib pack failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
error = std::string("can't open ") + log_filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t get_log_file_size()
|
||||
{
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
std::ifstream in(log_filename, std::ifstream::ate | std::ifstream::binary);
|
||||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ namespace tools
|
|||
return k;
|
||||
}
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error);
|
||||
uint64_t get_log_file_size();
|
||||
|
||||
class signal_handler
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ namespace
|
|||
const command_line::arg_descriptor<std::string> arg_generate_genesis = {"generate-genesis", "Generate genesis coinbase based on config file", "", true };
|
||||
const command_line::arg_descriptor<uint64_t> arg_genesis_split_amount = { "genesis-split-amount", "Set split amount for generating genesis block", 0, true };
|
||||
const command_line::arg_descriptor<std::string> arg_get_info_flags = { "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "", true };
|
||||
const command_line::arg_descriptor<int64_t> arg_set_peer_log_level = { "set-peer-log-level", "Set log level for remote peer", 0, true };
|
||||
const command_line::arg_descriptor<uint64_t> arg_download_peer_log = { "download-peer-log", "Download log from remote peer (starting offset)", 0, true };
|
||||
}
|
||||
|
||||
typedef COMMAND_REQUEST_STAT_INFO_T<t_currency_protocol_handler<core>::stat_info> COMMAND_REQUEST_STAT_INFO;
|
||||
|
|
@ -839,7 +841,166 @@ bool generate_and_print_keys()
|
|||
<< "PRIVATE KEY: " << epee::string_tools::pod_to_hex(sk);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class command_t>
|
||||
bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, levin::levin_client_impl2& transport, peerid_type& peer_id, typename command_t::request& req, typename command_t::response& rsp)
|
||||
{
|
||||
if (!transport.is_connected())
|
||||
{
|
||||
if (!transport.connect(command_line::get_arg(vm, arg_ip), static_cast<int>(command_line::get_arg(vm, arg_port)), static_cast<int>(command_line::get_arg(vm, arg_timeout))))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!peer_id)
|
||||
{
|
||||
COMMAND_REQUEST_PEER_ID::request id_req = AUTO_VAL_INIT(id_req);
|
||||
COMMAND_REQUEST_PEER_ID::response id_rsp = AUTO_VAL_INIT(id_rsp);
|
||||
if (!net_utils::invoke_remote_command2(COMMAND_REQUEST_PEER_ID::ID, id_req, id_rsp, transport))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
peer_id = id_rsp.my_id;
|
||||
}
|
||||
}
|
||||
|
||||
nodetool::proof_of_trust pot = AUTO_VAL_INIT(pot);
|
||||
pot.peer_id = peer_id;
|
||||
pot.time = time(NULL);
|
||||
crypto::public_key pubk = AUTO_VAL_INIT(pubk);
|
||||
string_tools::hex_to_pod(P2P_MAINTAINERS_PUB_KEY, pubk);
|
||||
crypto::hash h = tools::get_proof_of_trust_hash(pot);
|
||||
crypto::generate_signature(h, pubk, sk, pot.sign);
|
||||
|
||||
req.tr = pot;
|
||||
|
||||
return net_utils::invoke_remote_command2(command_t::ID, req, rsp, transport);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_set_peer_log_level(po::variables_map& vm)
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
if (!get_private_key(sk, vm))
|
||||
{
|
||||
std::cout << "ERROR: secret key error" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t log_level = command_line::get_arg(vm, arg_set_peer_log_level);
|
||||
if (log_level < LOG_LEVEL_0 || log_level > LOG_LEVEL_MAX)
|
||||
{
|
||||
std::cout << "Error: invalid log level value: " << log_level << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::request req = AUTO_VAL_INIT(req);
|
||||
req.new_log_level = log_level;
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if (!invoke_debug_command<COMMAND_SET_LOG_LEVEL>(vm, sk, transport, peer_id, req, rsp))
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_SET_LOG_LEVEL failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "OK! Log level changed: " << rsp.old_log_level << " -> " << rsp.current_log_level << ENDL;
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_download_peer_log(po::variables_map& vm)
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
if (!get_private_key(sk, vm))
|
||||
{
|
||||
std::cout << "ERROR: secret key error" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t start_offset = command_line::get_arg(vm, arg_download_peer_log);
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_REQUEST_LOG::request req = AUTO_VAL_INIT(req);
|
||||
COMMAND_REQUEST_LOG::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_LOG>(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty())
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Current log level: " << rsp.current_log_level << ENDL;
|
||||
std::cout << "Current log size: " << rsp.current_log_size << ENDL;
|
||||
|
||||
if (start_offset >= rsp.current_log_size)
|
||||
{
|
||||
std::cout << "ERROR: invalid start offset: " << start_offset << ", log size: " << rsp.current_log_size << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Downloading..." << ENDL;
|
||||
|
||||
std::string local_filename = tools::get_default_data_dir() + "/log_" + epee::string_tools::num_to_string_fast(peer_id) + ".log";
|
||||
std::ofstream log{ local_filename, std::ifstream::binary };
|
||||
if (!log)
|
||||
{
|
||||
std::cout << "Couldn't open " << local_filename << " for writing." << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t chunk_size = 1024 * 1024 * 5;
|
||||
uint64_t end_offset = start_offset;
|
||||
uint64_t bytes = 0;
|
||||
while (true)
|
||||
{
|
||||
req.log_chunk_offset = end_offset;
|
||||
req.log_chunk_size = std::min(chunk_size, rsp.current_log_size - req.log_chunk_offset);
|
||||
if (req.log_chunk_size == 0)
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_LOG>(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty())
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::unpack(rsp.log_chunk))
|
||||
{
|
||||
std::cout << "ERROR: zip unpack failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rsp.log_chunk.size() != req.log_chunk_size)
|
||||
{
|
||||
std::cout << "ERROR: unpacked size: " << rsp.log_chunk.size() << ", requested: " << req.log_chunk_size << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
log.write(rsp.log_chunk.c_str(), rsp.log_chunk.size());
|
||||
|
||||
end_offset += req.log_chunk_size;
|
||||
|
||||
std::cout << end_offset - start_offset << " bytes downloaded" << ENDL;
|
||||
}
|
||||
|
||||
std::cout << "Remote log from offset " << start_offset << " to offset " << end_offset << " (" << end_offset - start_offset << " bytes) " <<
|
||||
"was successfully downloaded to " << local_filename;
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
|
|
@ -874,7 +1035,9 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_genesis_split_amount);
|
||||
command_line::add_arg(desc_params, arg_get_info_flags);
|
||||
command_line::add_arg(desc_params, arg_log_journal_len);
|
||||
|
||||
command_line::add_arg(desc_params, arg_set_peer_log_level);
|
||||
command_line::add_arg(desc_params, arg_download_peer_log);
|
||||
|
||||
|
||||
|
||||
po::options_description desc_all;
|
||||
|
|
@ -931,6 +1094,14 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
return generate_genesis(command_line::get_arg(vm, arg_generate_genesis), 10000000000000000) ? 0 : 1;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_set_peer_log_level))
|
||||
{
|
||||
return handle_set_peer_log_level(vm) ? 0 : 1;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_download_peer_log))
|
||||
{
|
||||
return handle_download_peer_log(vm) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Not enough arguments." << ENDL;
|
||||
|
|
|
|||
|
|
@ -124,6 +124,8 @@ namespace nodetool
|
|||
HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_LOG, &node_server::handle_request_log)
|
||||
HANDLE_INVOKE_T2(COMMAND_SET_LOG_LEVEL, &node_server::handle_set_log_level)
|
||||
#endif
|
||||
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
|
||||
END_INVOKE_MAP2()
|
||||
|
|
@ -137,6 +139,8 @@ namespace nodetool
|
|||
int handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
|
||||
int handle_request_log(int command, COMMAND_REQUEST_LOG::request& arg, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context);
|
||||
int handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& arg, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context);
|
||||
private:
|
||||
#endif
|
||||
bool init_config();
|
||||
|
|
|
|||
|
|
@ -1039,6 +1039,7 @@ namespace nodetool
|
|||
rsp.connections_count = m_net_server.get_config_object().get_connections_count();
|
||||
rsp.incoming_connections_count = rsp.connections_count - get_outgoing_connections_count();
|
||||
rsp.version = PROJECT_VERSION_LONG;
|
||||
rsp.current_log_size = tools::get_log_file_size();
|
||||
m_payload_handler.get_stat_info(arg.pr, rsp.payload_info);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1080,7 +1081,44 @@ namespace nodetool
|
|||
rsp.my_id = m_config.m_peer_id;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_request_log(int command, COMMAND_REQUEST_LOG::request& req, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if (!check_trust(req.tr))
|
||||
{
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsp.current_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
tools::get_log_chunk_gzipped(req.log_chunk_offset, req.log_chunk_size, rsp.log_chunk, rsp.error);
|
||||
rsp.current_log_size = tools::get_log_file_size();
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& req, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if (!check_trust(req.tr))
|
||||
{
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsp.old_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
log_space::get_set_log_detalisation_level(true, static_cast<int>(req.new_log_level));
|
||||
rsp.current_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
|
||||
if (rsp.old_log_level != rsp.current_log_level)
|
||||
{
|
||||
LOG_PRINT_CC(context, "log level changed by debug command: " << rsp.old_log_level << " -> " << rsp.current_log_level, LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // #ifdef ALLOW_DEBUG_COMMANDS
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context)
|
||||
|
|
|
|||
|
|
@ -328,12 +328,14 @@ namespace nodetool
|
|||
std::string version;
|
||||
uint64_t connections_count;
|
||||
uint64_t incoming_connections_count;
|
||||
uint64_t current_log_size;
|
||||
payload_stat_info payload_info;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(version)
|
||||
KV_SERIALIZE(connections_count)
|
||||
KV_SERIALIZE(incoming_connections_count)
|
||||
KV_SERIALIZE(current_log_size)
|
||||
KV_SERIALIZE(payload_info)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
|
@ -397,7 +399,73 @@ namespace nodetool
|
|||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_REQUEST_LOG
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 7;
|
||||
|
||||
struct request
|
||||
{
|
||||
proof_of_trust tr;
|
||||
uint64_t log_chunk_offset;
|
||||
uint64_t log_chunk_size;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tr)
|
||||
KV_SERIALIZE(log_chunk_offset)
|
||||
KV_SERIALIZE(log_chunk_size)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
int64_t current_log_level;
|
||||
uint64_t current_log_size;
|
||||
std::string error;
|
||||
std::string log_chunk;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(current_log_level)
|
||||
KV_SERIALIZE(current_log_size)
|
||||
KV_SERIALIZE(error)
|
||||
KV_SERIALIZE(log_chunk)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_SET_LOG_LEVEL
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 8;
|
||||
|
||||
struct request
|
||||
{
|
||||
proof_of_trust tr;
|
||||
int64_t new_log_level;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tr)
|
||||
KV_SERIALIZE(new_log_level)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
int64_t old_log_level;
|
||||
int64_t current_log_level;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(old_log_level)
|
||||
KV_SERIALIZE(current_log_level)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
#endif // #ifdef ALLOW_DEBUG_COMMANDS
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue