forked from wownero/wownero
commit
df6026182a
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,46 +0,0 @@
|
||||
# Copyright (c) 2014-2016, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are
|
||||
# permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
# conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
# of conditions and the following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
set(connectivity_tool_sources
|
||||
conn_tool.cpp)
|
||||
|
||||
set(connectivity_tool_private_headers)
|
||||
|
||||
bitmonero_add_executable(connectivity_tool
|
||||
${connectivity_tool_sources}
|
||||
${connectivity_tool_private_headers})
|
||||
target_link_libraries(connectivity_tool
|
||||
LINK_PRIVATE
|
||||
cryptonote_core
|
||||
crypto
|
||||
common
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
${Boost_REGEX_LIBRARY}
|
||||
${Boost_CHRONO_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY})
|
@ -1,377 +0,0 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace epee;
|
||||
#include <boost/program_options.hpp>
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
#include "common/command_line.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "net/levin_client.h"
|
||||
#include "storages/levin_abstract_invoke2.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "storages/http_abstract_invoke.h"
|
||||
#include "net/http_client.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace cryptonote;
|
||||
using namespace nodetool;
|
||||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"};
|
||||
const command_line::arg_descriptor<size_t> arg_port = {"port", "set port"};
|
||||
const command_line::arg_descriptor<size_t> arg_rpc_port = {"rpc_port", "set rpc port"};
|
||||
const command_line::arg_descriptor<uint32_t, true> arg_timeout = {"timeout", "set timeout"};
|
||||
const command_line::arg_descriptor<std::string> arg_priv_key = {"private_key", "private key to subscribe debug command", "", true};
|
||||
const command_line::arg_descriptor<uint64_t> arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0};
|
||||
const command_line::arg_descriptor<bool> arg_generate_keys = {"generate_keys_pair", "generate private and public keys pair"};
|
||||
const command_line::arg_descriptor<bool> arg_request_stat_info = {"request_stat_info", "request statistics information"};
|
||||
const command_line::arg_descriptor<bool> arg_request_net_state = {"request_net_state", "request network state information (peer list, connections count)"};
|
||||
const command_line::arg_descriptor<bool> arg_get_daemon_info = {"rpc_get_daemon_info", "request daemon state info vie rpc (--rpc_port option should be set ).", "", true};
|
||||
}
|
||||
|
||||
typedef COMMAND_REQUEST_STAT_INFO_T<t_cryptonote_protocol_handler<core>::stat_info> COMMAND_REQUEST_STAT_INFO;
|
||||
|
||||
struct response_schema
|
||||
{
|
||||
std::string status;
|
||||
std::string COMMAND_REQUEST_STAT_INFO_status;
|
||||
std::string COMMAND_REQUEST_NETWORK_STATE_status;
|
||||
enableable<COMMAND_REQUEST_STAT_INFO::response> si_rsp;
|
||||
enableable<COMMAND_REQUEST_NETWORK_STATE::response> ns_rsp;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE(COMMAND_REQUEST_STAT_INFO_status)
|
||||
KV_SERIALIZE(COMMAND_REQUEST_NETWORK_STATE_status)
|
||||
KV_SERIALIZE(si_rsp)
|
||||
KV_SERIALIZE(ns_rsp)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
std::string get_response_schema_as_json(response_schema& rs)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{" << ENDL
|
||||
<< " \"status\": \"" << rs.status << "\"," << ENDL
|
||||
<< " \"COMMAND_REQUEST_NETWORK_STATE_status\": \"" << rs.COMMAND_REQUEST_NETWORK_STATE_status << "\"," << ENDL
|
||||
<< " \"COMMAND_REQUEST_STAT_INFO_status\": \"" << rs.COMMAND_REQUEST_STAT_INFO_status << "\"";
|
||||
if(rs.si_rsp.enabled)
|
||||
{
|
||||
ss << "," << ENDL << " \"si_rsp\": " << epee::serialization::store_t_to_json(rs.si_rsp.v, 1);
|
||||
}
|
||||
if(rs.ns_rsp.enabled)
|
||||
{
|
||||
ss << "," << ENDL << " \"ns_rsp\": {" << ENDL
|
||||
<< " \"local_time\": " << rs.ns_rsp.v.local_time << "," << ENDL
|
||||
<< " \"my_id\": \"" << rs.ns_rsp.v.my_id << "\"," << ENDL
|
||||
<< " \"connections_list\": [" << ENDL;
|
||||
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const connection_entry& ce, rs.ns_rsp.v.connections_list)
|
||||
{
|
||||
ss << " {\"peer_id\": \"" << ce.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(ce.adr.ip) << "\", \"port\": " << ce.adr.port << ", \"is_income\": "<< ce.is_income << "}";
|
||||
if(rs.ns_rsp.v.connections_list.size()-1 != i)
|
||||
ss << ",";
|
||||
ss << ENDL;
|
||||
i++;
|
||||
}
|
||||
ss << " ]," << ENDL;
|
||||
ss << " \"local_peerlist_white\": [" << ENDL;
|
||||
i = 0;
|
||||
BOOST_FOREACH(const peerlist_entry& pe, rs.ns_rsp.v.local_peerlist_white)
|
||||
{
|
||||
ss << " {\"peer_id\": \"" << pe.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(pe.adr.ip) << "\", \"port\": " << pe.adr.port << ", \"last_seen\": "<< rs.ns_rsp.v.local_time - pe.last_seen << "}";
|
||||
if(rs.ns_rsp.v.local_peerlist_white.size()-1 != i)
|
||||
ss << ",";
|
||||
ss << ENDL;
|
||||
i++;
|
||||
}
|
||||
ss << " ]," << ENDL;
|
||||
|
||||
ss << " \"local_peerlist_gray\": [" << ENDL;
|
||||
i = 0;
|
||||
BOOST_FOREACH(const peerlist_entry& pe, rs.ns_rsp.v.local_peerlist_gray)
|
||||
{
|
||||
ss << " {\"peer_id\": \"" << pe.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(pe.adr.ip) << "\", \"port\": " << pe.adr.port << ", \"last_seen\": "<< rs.ns_rsp.v.local_time - pe.last_seen << "}";
|
||||
if(rs.ns_rsp.v.local_peerlist_gray.size()-1 != i)
|
||||
ss << ",";
|
||||
ss << ENDL;
|
||||
i++;
|
||||
}
|
||||
ss << " ]" << ENDL << " }" << ENDL;
|
||||
}
|
||||
ss << "}";
|
||||
return std::move(ss.str());
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool print_COMMAND_REQUEST_STAT_INFO(const COMMAND_REQUEST_STAT_INFO::response& si)
|
||||
{
|
||||
std::cout << " ------ COMMAND_REQUEST_STAT_INFO ------ " << ENDL;
|
||||
std::cout << "Version: " << si.version << ENDL;
|
||||
std::cout << "OS Version: " << si.os_version << ENDL;
|
||||
std::cout << "Connections: " << si.connections_count << ENDL;
|
||||
std::cout << "INC Connections: " << si.incoming_connections_count << ENDL;
|
||||
|
||||
|
||||
std::cout << "Tx pool size: " << si.payload_info.tx_pool_size << ENDL;
|
||||
std::cout << "BC height: " << si.payload_info.blockchain_height << ENDL;
|
||||
std::cout << "Mining speed: " << si.payload_info.mining_speed << ENDL;
|
||||
std::cout << "Alternative blocks: " << si.payload_info.alternative_blocks << ENDL;
|
||||
std::cout << "Top block id: " << si.payload_info.top_block_id_str << ENDL;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool print_COMMAND_REQUEST_NETWORK_STATE(const COMMAND_REQUEST_NETWORK_STATE::response& ns)
|
||||
{
|
||||
std::cout << " ------ COMMAND_REQUEST_NETWORK_STATE ------ " << ENDL;
|
||||
std::cout << "Peer id: " << ns.my_id << ENDL;
|
||||
std::cout << "Active connections:" << ENDL;
|
||||
BOOST_FOREACH(const connection_entry& ce, ns.connections_list)
|
||||
{
|
||||
std::cout << ce.id << "\t" << string_tools::get_ip_string_from_int32(ce.adr.ip) << ":" << ce.adr.port << (ce.is_income ? "(INC)":"(OUT)") << ENDL;
|
||||
}
|
||||
|
||||
std::cout << "Peer list white:" << ns.my_id << ENDL;
|
||||
BOOST_FOREACH(const peerlist_entry& pe, ns.local_peerlist_white)
|
||||
{
|
||||
std::cout << pe.id << "\t" << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << pe.adr.port << "\t" << misc_utils::get_time_interval_string(ns.local_time - pe.last_seen) << ENDL;
|
||||
}
|
||||
|
||||
std::cout << "Peer list gray:" << ns.my_id << ENDL;
|
||||
BOOST_FOREACH(const peerlist_entry& pe, ns.local_peerlist_gray)
|
||||
{
|
||||
std::cout << pe.id << "\t" << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << pe.adr.port << "\t" << misc_utils::get_time_interval_string(ns.local_time - pe.last_seen) << ENDL;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_get_daemon_info(po::variables_map& vm)
|
||||
{
|
||||
if(!command_line::has_arg(vm, arg_rpc_port))
|
||||
{
|
||||
std::cout << "ERROR: rpc port not set" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
epee::net_utils::http::http_simple_client http_client;
|
||||
|
||||
cryptonote::COMMAND_RPC_GET_INFO::request req = AUTO_VAL_INIT(req);
|
||||
cryptonote::COMMAND_RPC_GET_INFO::response res = AUTO_VAL_INIT(res);
|
||||
std::string daemon_addr = command_line::get_arg(vm, arg_ip) + ":" + std::to_string(command_line::get_arg(vm, arg_rpc_port));
|
||||
bool r = net_utils::invoke_http_json_remote_command2(daemon_addr + "/getinfo", req, res, http_client, command_line::get_arg(vm, arg_timeout));
|
||||
if(!r)
|
||||
{
|
||||
std::cout << "ERROR: failed to invoke request" << ENDL;
|
||||
return false;
|
||||
}
|
||||
std::cout << "OK" << ENDL
|
||||
<< "height: " << res.height << ENDL
|
||||
<< "difficulty: " << res.difficulty << ENDL
|
||||
<< "tx_count: " << res.tx_count << ENDL
|
||||
<< "tx_pool_size: " << res.tx_pool_size << ENDL
|
||||
<< "alt_blocks_count: " << res.alt_blocks_count << ENDL
|
||||
<< "outgoing_connections_count: " << res.outgoing_connections_count << ENDL
|
||||
<< "incoming_connections_count: " << res.incoming_connections_count << ENDL
|
||||
<< "white_peerlist_size: " << res.white_peerlist_size << ENDL
|
||||
<< "grey_peerlist_size: " << res.grey_peerlist_size << ENDL;
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_request_stat(po::variables_map& vm, peerid_type peer_id)
|
||||
{
|
||||
|
||||
if(!command_line::has_arg(vm, arg_priv_key))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "secret key not set \"" << ENDL << "}";
|
||||
return false;
|
||||
}
|
||||
crypto::secret_key prvk = AUTO_VAL_INIT(prvk);
|
||||
if(!string_tools::hex_to_pod(command_line::get_arg(vm, arg_priv_key) , prvk))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "wrong secret key set \"" << ENDL << "}";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
response_schema rs = AUTO_VAL_INIT(rs);
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
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 << "}";
|
||||
return false;
|
||||
}else
|
||||
rs.status = "OK";
|
||||
|
||||
if(!peer_id)
|
||||
{
|
||||
COMMAND_REQUEST_PEER_ID::request req = AUTO_VAL_INIT(req);
|
||||
COMMAND_REQUEST_PEER_ID::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_PEER_ID::ID, req, 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 << "}";
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
peer_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(::config::P2P_REMOTE_DEBUG_TRUSTED_PUB_KEY, pubk);
|
||||
crypto::hash h = tools::get_proof_of_trust_hash(pot);
|
||||
crypto::generate_signature(h, pubk, prvk, pot.sign);
|
||||
|
||||
if(command_line::get_arg(vm, arg_request_stat_info))
|
||||
{
|
||||
COMMAND_REQUEST_STAT_INFO::request req = AUTO_VAL_INIT(req);
|
||||
req.tr = pot;
|
||||
if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_STAT_INFO::ID, req, rs.si_rsp.v, transport))
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "ERROR: " << "Failed to invoke remote command COMMAND_REQUEST_STAT_INFO to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port);
|
||||
rs.COMMAND_REQUEST_STAT_INFO_status = ss.str();
|
||||
}else
|
||||
{
|
||||
rs.si_rsp.enabled = true;
|
||||
rs.COMMAND_REQUEST_STAT_INFO_status = "OK";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(command_line::get_arg(vm, arg_request_net_state))
|
||||
{
|
||||
++pot.time;
|
||||
h = tools::get_proof_of_trust_hash(pot);
|
||||
crypto::generate_signature(h, pubk, prvk, pot.sign);
|
||||
COMMAND_REQUEST_NETWORK_STATE::request req = AUTO_VAL_INIT(req);
|
||||
req.tr = pot;
|
||||
if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_NETWORK_STATE::ID, req, rs.ns_rsp.v, transport))
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "ERROR: " << "Failed to invoke remote command COMMAND_REQUEST_NETWORK_STATE to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port);
|
||||
rs.COMMAND_REQUEST_NETWORK_STATE_status = ss.str();
|
||||
}else
|
||||
{
|
||||
rs.ns_rsp.enabled = true;
|
||||
rs.COMMAND_REQUEST_NETWORK_STATE_status = "OK";
|
||||
}
|
||||
}
|
||||
std::cout << get_response_schema_as_json(rs);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool generate_and_print_keys()
|
||||
{
|
||||
crypto::public_key pk = AUTO_VAL_INIT(pk);
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
generate_keys(pk, sk);
|
||||
std::cout << "PUBLIC KEY: " << epee::string_tools::pod_to_hex(pk) << ENDL
|
||||
<< "PRIVATE KEY: " << epee::string_tools::pod_to_hex(sk);
|
||||
return true;
|
||||
}
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
string_tools::set_module_name_and_folder(argv[0]);
|
||||
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0);
|
||||
|
||||
// Declare the supported options.
|
||||
po::options_description desc_general("General options");
|
||||
command_line::add_arg(desc_general, command_line::arg_help);
|
||||
|
||||
po::options_description desc_params("Connectivity options");
|
||||
command_line::add_arg(desc_params, arg_ip);
|
||||
command_line::add_arg(desc_params, arg_port);
|
||||
command_line::add_arg(desc_params, arg_rpc_port);
|
||||
command_line::add_arg(desc_params, arg_timeout);
|
||||
command_line::add_arg(desc_params, arg_request_stat_info);
|
||||
command_line::add_arg(desc_params, arg_request_net_state);
|
||||
command_line::add_arg(desc_params, arg_generate_keys);
|
||||
command_line::add_arg(desc_params, arg_peer_id);
|
||||
command_line::add_arg(desc_params, arg_priv_key);
|
||||
command_line::add_arg(desc_params, arg_get_daemon_info);
|
||||
|
||||
|
||||
po::options_description desc_all;
|
||||
desc_all.add(desc_general).add(desc_params);
|
||||
|
||||
po::variables_map vm;
|
||||
bool r = command_line::handle_error_helper(desc_all, [&]()
|
||||
{
|
||||
po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm);
|
||||
if (command_line::get_arg(vm, command_line::arg_help))
|
||||
{
|
||||
std::cout << desc_all << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
po::store(command_line::parse_command_line(argc, argv, desc_params, false), vm);
|
||||
po::notify(vm);
|
||||
|
||||
return true;
|
||||
});
|
||||
if (!r)
|
||||
return 1;
|
||||
|
||||
if(command_line::has_arg(vm, arg_request_stat_info) || command_line::has_arg(vm, arg_request_net_state))
|
||||
{
|
||||
return handle_request_stat(vm, command_line::get_arg(vm, arg_peer_id)) ? 0:1;
|
||||
}
|
||||
if(command_line::has_arg(vm, arg_get_daemon_info))
|
||||
{
|
||||
return handle_get_daemon_info(vm) ? 0:1;
|
||||
}
|
||||
else if(command_line::has_arg(vm, arg_generate_keys))
|
||||
{
|
||||
return generate_and_print_keys() ? 0:1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Not enough arguments." << ENDL;
|
||||
std::cerr << desc_all << ENDL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,280 +0,0 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "checkpoints_create.h"
|
||||
#include "common/dns_utils.h"
|
||||
#include "include_base_utils.h"
|
||||
#include <sstream>
|
||||
#include <random>
|
||||
#include "storages/portable_storage_template_helper.h" // epee json include
|
||||
|
||||
namespace
|
||||
{
|
||||
bool dns_records_match(const std::vector<std::string>& a, const std::vector<std::string>& b)
|
||||
{
|
||||
if (a.size() != b.size()) return false;
|
||||
|
||||
for (const auto& record_in_a : a)
|
||||
{
|
||||
bool ok = false;
|
||||
for (const auto& record_in_b : b)
|
||||
{
|
||||
if (record_in_a == record_in_b)
|
||||
{
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
struct t_hashline
|
||||
{
|
||||
uint64_t height;
|
||||
std::string hash;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE(hash)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct t_hash_json {
|
||||
std::vector<t_hashline> hashlines;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(hashlines)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
bool create_checkpoints(cryptonote::checkpoints& checkpoints)
|
||||
{
|
||||
ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148");
|
||||
ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381");
|
||||
ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d");
|
||||
ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876");
|
||||
ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2");
|
||||
ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25");
|
||||
ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6");
|
||||
ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c");
|
||||
ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3");
|
||||
ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698");
|
||||
ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2");
|
||||
ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb");
|
||||
ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063");
|
||||
ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553");
|
||||
ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61");
|
||||
ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf");
|
||||
ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131");
|
||||
ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8");
|
||||
ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d");
|
||||
ADD_CHECKPOINT(300000, "0c1cd46df6ccff90ec4ab493281f2583c344cd62216c427628990fe9db1bb8b6");
|
||||
ADD_CHECKPOINT(400000, "1b2b0e7a30e59691491529a3d506d1ba3d6052d0f6b52198b7330b28a6f1b6ac");
|
||||
ADD_CHECKPOINT(450000, "4d098b511ca97723e81737c448343cfd4e6dadb3d8a0e757c6e4d595e6e48357");
|
||||
ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831");
|
||||
ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02");
|
||||
ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5");
|
||||
ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd");
|
||||
ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60");
|
||||
ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337");
|
||||
ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath)
|
||||
{
|
||||
boost::system::error_code errcode;
|
||||
if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode)))
|
||||
{
|
||||
LOG_PRINT_L1("Blockchain checkpoints file not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_PRINT_L1("Adding checkpoints from blockchain hashfile");
|
||||
|
||||
uint64_t prev_max_height = checkpoints.get_max_height();
|
||||
LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height);
|
||||
t_hash_json hashes;
|
||||
epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath);
|
||||
for (std::vector<t_hashline>::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); )
|
||||
{
|
||||
uint64_t height;
|
||||
height = it->height;
|
||||
if (height <= prev_max_height) {
|
||||
LOG_PRINT_L1("ignoring checkpoint height " << height);
|
||||
} else {
|
||||
std::string blockhash = it->hash;
|
||||
LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash);
|
||||
ADD_CHECKPOINT(height, blockhash);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet)
|
||||
{
|
||||
// All four MoneroPulse domains have DNSSEC on and valid
|
||||
static const std::vector<std::string> dns_urls = { "checkpoints.moneropulse.se"
|
||||
, "checkpoints.moneropulse.org"
|
||||
, "checkpoints.moneropulse.net"
|
||||
, "checkpoints.moneropulse.co"
|
||||
};
|
||||
|
||||
static const std::vector<std::string> testnet_dns_urls = { "testpoints.moneropulse.se"
|
||||
, "testpoints.moneropulse.org"
|
||||
, "testpoints.moneropulse.net"
|
||||
, "testpoints.moneropulse.co"
|
||||
};
|
||||
|
||||
std::vector<std::vector<std::string> > records;
|
||||
records.resize(dns_urls.size());
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1);
|
||||
size_t first_index = dis(gen);
|
||||
|
||||
bool avail, valid;
|
||||
size_t cur_index = first_index;
|
||||
do
|
||||
{
|
||||
std::string url;
|
||||
if (testnet)
|
||||
{
|
||||
url = testnet_dns_urls[cur_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
url = dns_urls[cur_index];
|
||||
}
|
||||
|
||||
records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid);
|
||||
if (!avail)
|
||||
{
|
||||
records[cur_index].clear();
|
||||
LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping.");
|
||||
}
|
||||
if (!valid)
|
||||
{
|
||||
records[cur_index].clear();
|
||||
LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping.");
|
||||
}
|
||||
|
||||
cur_index++;
|
||||
if (cur_index == dns_urls.size())
|
||||
{
|
||||
cur_index = 0;
|
||||
}
|
||||
records[cur_index].clear();
|
||||
} while (cur_index != first_index);
|
||||
|
||||
size_t num_valid_records = 0;
|
||||
|
||||
for( const auto& record_set : records)
|
||||
{
|
||||
if (record_set.size() != 0)
|
||||
{
|
||||
num_valid_records++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_valid_records < 2)
|
||||
{
|
||||
LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received");
|
||||
return true;
|
||||
}
|
||||
|
||||
int good_records_index = -1;
|
||||
for (size_t i = 0; i < records.size() - 1; ++i)
|
||||
{
|
||||
if (records[i].size() == 0) continue;
|
||||
|
||||
for (size_t j = i + 1; j < records.size(); ++j)
|
||||
{
|
||||
if (dns_records_match(records[i], records[j]))
|
||||
{
|
||||
good_records_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (good_records_index >= 0) break;
|
||||
}
|
||||
|
||||
if (good_records_index < 0)
|
||||
{
|
||||
LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched");
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto& record : records[good_records_index])
|
||||
{
|
||||
auto pos = record.find(":");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
uint64_t height;
|
||||
crypto::hash hash;
|
||||
|
||||
// parse the first part as uint64_t,
|
||||
// if this fails move on to the next record
|
||||
std::stringstream ss(record.substr(0, pos));
|
||||
if (!(ss >> height))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse the second part as crypto::hash,
|
||||
// if this fails move on to the next record
|
||||
std::string hashStr = record.substr(pos + 1);
|
||||
if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ADD_CHECKPOINT(height, hashStr);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath)
|
||||
{
|
||||
// TODO: replace hard-coded url with const string or #define
|
||||
return (load_checkpoints_from_json(checkpoints, json_hashfile_fullpath) && load_checkpoints_from_dns(checkpoints));
|
||||
}
|
||||
|
||||
} // namespace cryptonote
|
@ -1,48 +0,0 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "checkpoints.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false);
|
||||
#define JSON_HASH_FILE_NAME "checkpoints.json"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
bool create_checkpoints(cryptonote::checkpoints& checkpoints);
|
||||
|
||||
bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath);
|
||||
bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet = false);
|
||||
bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath);
|
||||
|
||||
} // namespace cryptonote
|
@ -1,4 +1,4 @@
|
||||
#define MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define MONERO_VERSION "0.9.1.0"
|
||||
#define MONERO_VERSION "0.9.3.0"
|
||||
#define MONERO_RELEASE_NAME "Hydrogen Helix"
|
||||
#define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG
|
||||
|
@ -1,31 +0,0 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1
|
||||
|
||||
mQENBFQwICMBCACyHKYHaSEdNyE8kqYm+V37IsX5xxqMTkOCuVmaWt8i8FP2aPDz
|
||||
TgsITQ8tHoJubL0wh/y6Z/KQY8cSWT/JU39gP64I1XdGVgaPErF3kZ7n2jh+K5HY
|
||||
vBWrFvw4Xj2XvHaJZW6rVVX5dc4rxqnnOjfKTPI6/tQhT16dwbMuCyZOyMfStAF9
|
||||
q+14I9M2MAbMlgNO0el0aR3GMVjoDeaWBk/qWxTaHjyOBAVyryoFpwIl7Gmwkk1d
|
||||
+jv4542LjJOiiwBEDcWUmNvlsRk5sXMcXImJSpaCN1Ta9Eyu2NBIK/qAbuC6YgLe
|
||||
nn/0DaA7TOpeIMU/WNq/Dpbathst+fMJNK6BABEBAAG0JkFsZXhhbmRlciBBYnJh
|
||||
bW92IDxhYWJyYW1vdkBnbWFpbC5jb20+iQE+BBMBAgAoBQJUMCAjAhsDBQkDwmcA
|
||||
BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA/57nKbsMV+F/+B/9f7C1iiEFD
|
||||
18Af48WLJXZaJJTqxMeWzztWhZ2LS27rFOGJcj50UeON7aVu8LWU8gvyPJct6wJA
|
||||
T1hvPWc6TTsbYp8KHP/nUfUWWV+np0qVSj91eGHp7NjAxXYe4NnWt1JUtINxvNll
|
||||
BKY2l0MHHHKwuWxky6zug48CToB8Y0RBDUgFM0pmnCzmySs6OAJbLmnnvesTDFZk
|
||||
m6wycq4/SrbVByTZHVqBmZNnypMQxbqXTti9ltpXWqO89RpQQ+QBQQlrNy9QRHJq
|
||||
VW9Qn5eL4O4IdmXpHqln1ppSu2il+pqQCGc5O9xFxqG6YRHljQEngBfgKLxOsqa1
|
||||
OGJHu1pLyUYRuQENBFQwICMBCACmQ+1DRgm9AMNo4iDur47obDzUTQ/1g2ah1+AT
|
||||
IYNhhltBD3jURsRZ6lMeancxU2/6hyUzCon5ETKfnF0+ujqldSDuo+XY9CDgmXLC
|
||||
s3wPAKZvyjScwMFTyW1hGfyT9SFwYVDaXOeW+VrJ97Xh5FWHx8LU7eieYIl8tOUY
|
||||
YWEeIps/y5zBkk7bB4LVNVc3AlKPS4vb/py5szA5fMg8ix/ggvpq8be4BnImP3a1
|
||||
yrl+W9HUtcTs8jBnFLMoZYaUklZ9LR7yfnjhhtKqW833UB07qYQY//dJGy4kVnit
|
||||
M5LX9VKa+wnWsgP+w5jElPX0bweV6+V/yFRhjLLwV7dv/MJnABEBAAGJASUEGAEC
|
||||
AA8FAlQwICMCGwwFCQPCZwAACgkQP+e5ym7DFfgrvAf/bnQD5iR/HiNsH0HQE96G
|
||||
Wsrr9VW/ucnm06pd1D/r7ogYcVWuNIglx3QdvFla4uZDvYR0PhyjNrOyPzUgLWp/
|
||||
fjQw9buyI3BawAScbPuN06zHLUIvDQpaPq2+uBRq7sCcdsox6sMiUH6x5QcD3lbR
|
||||
nh6aAGwSkTabW5a/GVZTIHSicGbhXUaIIh3w+sQZ/y5xTVjgVi4I4XdrxOZoo5RN
|
||||
nF5oyn74n5p9euxJMWgvC/tz/bD7VKYWJHRnuyeumLTPudLjPFFQpTX+I+gMJ5FT
|
||||
Vs7byaOlrZbQxzXd4G0uBnCvJ1FH3cL6Ddqlsz/l2WzddMknMbVMn7+fSVMdpbIm
|
||||
hw==
|
||||
=7XDh
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
@ -0,0 +1,44 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1
|
||||
|
||||
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
|
||||
GQ==
|
||||
=sUzZ
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
Loading…
Reference in new issue