simplewallet: add public_nodes command
Lists nodes exposing their RPC port for public use
This commit is contained in:
parent
2899379791
commit
ffa46026b5
|
@ -116,7 +116,7 @@ namespace cryptonote
|
||||||
MAP_URI_AUTO_JON2_IF("/mining_status", on_mining_status, COMMAND_RPC_MINING_STATUS, !m_restricted)
|
MAP_URI_AUTO_JON2_IF("/mining_status", on_mining_status, COMMAND_RPC_MINING_STATUS, !m_restricted)
|
||||||
MAP_URI_AUTO_JON2_IF("/save_bc", on_save_bc, COMMAND_RPC_SAVE_BC, !m_restricted)
|
MAP_URI_AUTO_JON2_IF("/save_bc", on_save_bc, COMMAND_RPC_SAVE_BC, !m_restricted)
|
||||||
MAP_URI_AUTO_JON2_IF("/get_peer_list", on_get_peer_list, COMMAND_RPC_GET_PEER_LIST, !m_restricted)
|
MAP_URI_AUTO_JON2_IF("/get_peer_list", on_get_peer_list, COMMAND_RPC_GET_PEER_LIST, !m_restricted)
|
||||||
MAP_URI_AUTO_JON2_IF("/get_public_nodes", on_get_public_nodes, COMMAND_RPC_GET_PUBLIC_NODES, !m_restricted)
|
MAP_URI_AUTO_JON2("/get_public_nodes", on_get_public_nodes, COMMAND_RPC_GET_PUBLIC_NODES)
|
||||||
MAP_URI_AUTO_JON2_IF("/set_log_hash_rate", on_set_log_hash_rate, COMMAND_RPC_SET_LOG_HASH_RATE, !m_restricted)
|
MAP_URI_AUTO_JON2_IF("/set_log_hash_rate", on_set_log_hash_rate, COMMAND_RPC_SET_LOG_HASH_RATE, !m_restricted)
|
||||||
MAP_URI_AUTO_JON2_IF("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL, !m_restricted)
|
MAP_URI_AUTO_JON2_IF("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL, !m_restricted)
|
||||||
MAP_URI_AUTO_JON2_IF("/set_log_categories", on_set_log_categories, COMMAND_RPC_SET_LOG_CATEGORIES, !m_restricted)
|
MAP_URI_AUTO_JON2_IF("/set_log_categories", on_set_log_categories, COMMAND_RPC_SET_LOG_CATEGORIES, !m_restricted)
|
||||||
|
|
|
@ -1216,17 +1216,19 @@ namespace cryptonote
|
||||||
std::string host;
|
std::string host;
|
||||||
uint64_t last_seen;
|
uint64_t last_seen;
|
||||||
uint16_t rpc_port;
|
uint16_t rpc_port;
|
||||||
|
uint32_t rpc_credits_per_hash;
|
||||||
|
|
||||||
public_node() = delete;
|
public_node(): last_seen(0), rpc_port(0), rpc_credits_per_hash(0) {}
|
||||||
|
|
||||||
public_node(const peer &peer)
|
public_node(const peer &peer)
|
||||||
: host(peer.host), last_seen(peer.last_seen), rpc_port(peer.rpc_port)
|
: host(peer.host), last_seen(peer.last_seen), rpc_port(peer.rpc_port), rpc_credits_per_hash(peer.rpc_credits_per_hash)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(host)
|
KV_SERIALIZE(host)
|
||||||
KV_SERIALIZE(last_seen)
|
KV_SERIALIZE(last_seen)
|
||||||
KV_SERIALIZE(rpc_port)
|
KV_SERIALIZE(rpc_port)
|
||||||
|
KV_SERIALIZE(rpc_credits_per_hash)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,3 +47,4 @@
|
||||||
#define COST_PER_FEE_ESTIMATE 1
|
#define COST_PER_FEE_ESTIMATE 1
|
||||||
#define COST_PER_SYNC_INFO 2
|
#define COST_PER_SYNC_INFO 2
|
||||||
#define COST_PER_HARD_FORK_INFO 1
|
#define COST_PER_HARD_FORK_INFO 1
|
||||||
|
#define COST_PER_PEER_LIST 2
|
||||||
|
|
|
@ -262,6 +262,7 @@ namespace
|
||||||
const char* USAGE_FROZEN("frozen <key_image>");
|
const char* USAGE_FROZEN("frozen <key_image>");
|
||||||
const char* USAGE_LOCK("lock");
|
const char* USAGE_LOCK("lock");
|
||||||
const char* USAGE_NET_STATS("net_stats");
|
const char* USAGE_NET_STATS("net_stats");
|
||||||
|
const char* USAGE_PUBLIC_NODES("public_nodes");
|
||||||
const char* USAGE_WELCOME("welcome");
|
const char* USAGE_WELCOME("welcome");
|
||||||
const char* USAGE_RPC_PAYMENT_INFO("rpc_payment_info");
|
const char* USAGE_RPC_PAYMENT_INFO("rpc_payment_info");
|
||||||
const char* USAGE_START_MINING_FOR_RPC("start_mining_for_rpc");
|
const char* USAGE_START_MINING_FOR_RPC("start_mining_for_rpc");
|
||||||
|
@ -2247,6 +2248,45 @@ bool simple_wallet::net_stats(const std::vector<std::string> &args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool simple_wallet::public_nodes(const std::vector<std::string> &args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto nodes = m_wallet->get_public_nodes(false);
|
||||||
|
m_claimed_cph.clear();
|
||||||
|
if (nodes.empty())
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("No known public nodes");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::sort(nodes.begin(), nodes.end(), [](const public_node &node0, const public_node &node1) {
|
||||||
|
if (node0.rpc_credits_per_hash && node1.rpc_credits_per_hash == 0)
|
||||||
|
return true;
|
||||||
|
if (node0.rpc_credits_per_hash && node1.rpc_credits_per_hash)
|
||||||
|
return node0.rpc_credits_per_hash < node1.rpc_credits_per_hash;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const uint64_t now = time(NULL);
|
||||||
|
message_writer() << boost::format("%32s %12s %16s") % tr("address") % tr("credits/hash") % tr("last_seen");
|
||||||
|
for (const auto &node: nodes)
|
||||||
|
{
|
||||||
|
const float cph = node.rpc_credits_per_hash / RPC_CREDITS_PER_HASH_SCALE;
|
||||||
|
char cphs[9];
|
||||||
|
snprintf(cphs, sizeof(cphs), "%.3f", cph);
|
||||||
|
const std::string last_seen = node.last_seen == 0 ? tr("never") : get_human_readable_timespan(std::chrono::seconds(now - node.last_seen));
|
||||||
|
std::string host = node.host + ":" + std::to_string(node.rpc_port);
|
||||||
|
message_writer() << boost::format("%32s %12s %16s") % host % cphs % last_seen;
|
||||||
|
m_claimed_cph[host] = node.rpc_credits_per_hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Error retrieving public node list: ") << e.what();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool simple_wallet::welcome(const std::vector<std::string> &args)
|
bool simple_wallet::welcome(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
message_writer() << tr("Welcome to Monero, the private cryptocurrency.");
|
message_writer() << tr("Welcome to Monero, the private cryptocurrency.");
|
||||||
|
@ -3525,6 +3565,10 @@ simple_wallet::simple_wallet()
|
||||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::net_stats, _1),
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::net_stats, _1),
|
||||||
tr(USAGE_NET_STATS),
|
tr(USAGE_NET_STATS),
|
||||||
tr("Prints simple network stats"));
|
tr("Prints simple network stats"));
|
||||||
|
m_cmd_binder.set_handler("public_nodes",
|
||||||
|
boost::bind(&simple_wallet::public_nodes, this, _1),
|
||||||
|
tr(USAGE_PUBLIC_NODES),
|
||||||
|
tr("Lists known public nodes"));
|
||||||
m_cmd_binder.set_handler("welcome",
|
m_cmd_binder.set_handler("welcome",
|
||||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::welcome, _1),
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::welcome, _1),
|
||||||
tr(USAGE_WELCOME),
|
tr(USAGE_WELCOME),
|
||||||
|
@ -5260,24 +5304,7 @@ bool simple_wallet::check_daemon_rpc_prices(const std::string &daemon_url, uint3
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string host = node.host + ":" + std::to_string(node.rpc_port);
|
fail_msg_writer() << tr("Error checking daemon RPC access prices");
|
||||||
if (host == daemon_url)
|
|
||||||
{
|
|
||||||
claimed_cph = node.rpc_credits_per_hash;
|
|
||||||
bool payment_required;
|
|
||||||
uint64_t credits, diff, credits_per_hash_found, height;
|
|
||||||
uint32_t cookie;
|
|
||||||
cryptonote::blobdata hashing_blob;
|
|
||||||
if (m_wallet->get_rpc_payment_info(false, payment_required, credits, diff, credits_per_hash_found, hashing_blob, height, cookie) && payment_required)
|
|
||||||
{
|
|
||||||
actual_cph = RPC_CREDITS_PER_HASH_SCALE * (credits_per_hash_found / (float)diff);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail_msg_writer() << tr("Error checking daemon RPC access prices");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
|
@ -5313,7 +5340,7 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
|
||||||
// If no port has been provided, use the default from config
|
// If no port has been provided, use the default from config
|
||||||
if (!match[3].length())
|
if (!match[3].length())
|
||||||
{
|
{
|
||||||
int daemon_port = get_config(m_wallet->nettype()).RPC_DEFAULT_PORT;
|
uint16_t daemon_port = get_config(m_wallet->nettype()).RPC_DEFAULT_PORT;
|
||||||
daemon_url = match[1] + match[2] + std::string(":") + std::to_string(daemon_port);
|
daemon_url = match[1] + match[2] + std::string(":") + std::to_string(daemon_port);
|
||||||
} else {
|
} else {
|
||||||
daemon_url = args[0];
|
daemon_url = args[0];
|
||||||
|
@ -5346,8 +5373,27 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
|
||||||
}
|
}
|
||||||
catch (const std::exception &e) { }
|
catch (const std::exception &e) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!try_connect_to_daemon())
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Failed to connect to daemon");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (m_wallet->is_trusted_daemon() ? tr("trusted") : tr("untrusted"));
|
success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (m_wallet->is_trusted_daemon() ? tr("trusted") : tr("untrusted"));
|
||||||
|
|
||||||
|
// check whether the daemon's prices match the claim, and disconnect if not, to disincentivize daemons lying
|
||||||
|
uint32_t actual_cph, claimed_cph;
|
||||||
|
if (check_daemon_rpc_prices(daemon_url, actual_cph, claimed_cph))
|
||||||
|
{
|
||||||
|
if (actual_cph < claimed_cph)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Daemon RPC credits/hash is less than was claimed. Either this daemon is cheating, or it changed its setup recently.");
|
||||||
|
fail_msg_writer() << tr("Claimed: ") << claimed_cph / (float)RPC_CREDITS_PER_HASH_SCALE;
|
||||||
|
fail_msg_writer() << tr("Actual: ") << actual_cph / (float)RPC_CREDITS_PER_HASH_SCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_daemon_rpc_payment_message_displayed = false;
|
m_daemon_rpc_payment_message_displayed = false;
|
||||||
} else {
|
} else {
|
||||||
fail_msg_writer() << tr("This does not seem to be a valid daemon URL.");
|
fail_msg_writer() << tr("This does not seem to be a valid daemon URL.");
|
||||||
|
|
|
@ -257,6 +257,7 @@ namespace cryptonote
|
||||||
bool start_mining_for_rpc(const std::vector<std::string> &args);
|
bool start_mining_for_rpc(const std::vector<std::string> &args);
|
||||||
bool stop_mining_for_rpc(const std::vector<std::string> &args);
|
bool stop_mining_for_rpc(const std::vector<std::string> &args);
|
||||||
bool net_stats(const std::vector<std::string>& args);
|
bool net_stats(const std::vector<std::string>& args);
|
||||||
|
bool public_nodes(const std::vector<std::string>& args);
|
||||||
bool welcome(const std::vector<std::string>& args);
|
bool welcome(const std::vector<std::string>& args);
|
||||||
bool version(const std::vector<std::string>& args);
|
bool version(const std::vector<std::string>& args);
|
||||||
bool on_unknown_command(const std::vector<std::string>& args);
|
bool on_unknown_command(const std::vector<std::string>& args);
|
||||||
|
@ -335,6 +336,8 @@ namespace cryptonote
|
||||||
|
|
||||||
void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon);
|
void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon);
|
||||||
|
|
||||||
|
bool check_daemon_rpc_prices(const std::string &daemon_url, uint32_t &actual_cph, uint32_t &claimed_cph);
|
||||||
|
|
||||||
//----------------- i_wallet2_callback ---------------------
|
//----------------- i_wallet2_callback ---------------------
|
||||||
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
|
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
|
||||||
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time);
|
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time);
|
||||||
|
@ -457,6 +460,8 @@ namespace cryptonote
|
||||||
float m_rpc_payment_hash_rate;
|
float m_rpc_payment_hash_rate;
|
||||||
std::atomic<bool> m_suspend_rpc_payment_mining;
|
std::atomic<bool> m_suspend_rpc_payment_mining;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, uint32_t> m_claimed_cph;
|
||||||
|
|
||||||
// MMS
|
// MMS
|
||||||
mms::message_store& get_message_store() const { return m_wallet->get_message_store(); };
|
mms::message_store& get_message_store() const { return m_wallet->get_message_store(); };
|
||||||
mms::multisig_wallet_state get_multisig_wallet_state() const { return m_wallet->get_multisig_wallet_state(); };
|
mms::multisig_wallet_state get_multisig_wallet_state() const { return m_wallet->get_multisig_wallet_state(); };
|
||||||
|
|
|
@ -13549,4 +13549,25 @@ uint64_t wallet2::get_bytes_received() const
|
||||||
{
|
{
|
||||||
return m_http_client.get_bytes_received();
|
return m_http_client.get_bytes_received();
|
||||||
}
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
|
||||||
|
{
|
||||||
|
cryptonote::COMMAND_RPC_GET_PUBLIC_NODES::request req = AUTO_VAL_INIT(req);
|
||||||
|
cryptonote::COMMAND_RPC_GET_PUBLIC_NODES::response res = AUTO_VAL_INIT(res);
|
||||||
|
|
||||||
|
req.white = true;
|
||||||
|
req.gray = !white_only;
|
||||||
|
|
||||||
|
{
|
||||||
|
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||||
|
bool r = epee::net_utils::invoke_http_json("/get_public_nodes", req, res, m_http_client, rpc_timeout);
|
||||||
|
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/get_public_nodes");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cryptonote::public_node> nodes;
|
||||||
|
nodes = res.white;
|
||||||
|
nodes.reserve(nodes.size() + res.gray.size());
|
||||||
|
std::copy(res.gray.begin(), res.gray.end(), std::back_inserter(nodes));
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -886,6 +886,8 @@ private:
|
||||||
uint64_t get_last_block_reward() const { return m_last_block_reward; }
|
uint64_t get_last_block_reward() const { return m_last_block_reward; }
|
||||||
uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; }
|
uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; }
|
||||||
|
|
||||||
|
std::vector<cryptonote::public_node> get_public_nodes(bool white_only = true);
|
||||||
|
|
||||||
template <class t_archive>
|
template <class t_archive>
|
||||||
inline void serialize(t_archive &a, const unsigned int ver)
|
inline void serialize(t_archive &a, const unsigned int ver)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue