mirror of
https://github.com/wownero/wownero.git
synced 2026-11-14 04:13:54 +01:00
rpc: remove pay-to-use RPC on node side
Co-authored-by: tobtoht <tob@featherwallet.org> Co-authored-by: SNeedlewoods <sneedlewoods_1@protonmail.com>
This commit is contained in:
co-authored by
tobtoht
SNeedlewoods
parent
5e44d79824
commit
9b337ca01f
+6
-446
@@ -54,8 +54,6 @@ using namespace epee;
|
||||
#include "crypto/hash.h"
|
||||
#include "rpc/rpc_args.h"
|
||||
#include "rpc/rpc_handler.h"
|
||||
#include "rpc/rpc_payment_costs.h"
|
||||
#include "rpc/rpc_payment_signature.h"
|
||||
#include "core_rpc_server_error_codes.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "version.h"
|
||||
@@ -159,10 +157,6 @@ namespace cryptonote
|
||||
command_line::add_arg(desc, arg_bootstrap_daemon_login);
|
||||
command_line::add_arg(desc, arg_bootstrap_daemon_proxy);
|
||||
cryptonote::rpc_args::init_options(desc, true);
|
||||
command_line::add_arg(desc, arg_rpc_payment_address);
|
||||
command_line::add_arg(desc, arg_rpc_payment_difficulty);
|
||||
command_line::add_arg(desc, arg_rpc_payment_credits);
|
||||
command_line::add_arg(desc, arg_rpc_payment_allow_free_loopback);
|
||||
command_line::add_arg(desc, arg_rpc_max_connections_per_public_ip);
|
||||
command_line::add_arg(desc, arg_rpc_max_connections_per_private_ip);
|
||||
command_line::add_arg(desc, arg_rpc_max_connections);
|
||||
@@ -177,7 +171,6 @@ namespace cryptonote
|
||||
, m_p2p(p2p)
|
||||
, m_was_bootstrap_ever_used(false)
|
||||
, disable_rpc_ban(false)
|
||||
, m_rpc_payment_allow_free_loopback(false)
|
||||
{}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::set_bootstrap_daemon(
|
||||
@@ -194,7 +187,7 @@ namespace cryptonote
|
||||
return set_bootstrap_daemon(address, credentials, proxy);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t credits_per_hash_threshold/* = 0*/)
|
||||
std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t/* = 0*/)
|
||||
{
|
||||
COMMAND_RPC_GET_PUBLIC_NODES::request request;
|
||||
COMMAND_RPC_GET_PUBLIC_NODES::response response;
|
||||
@@ -209,16 +202,10 @@ namespace cryptonote
|
||||
|
||||
std::map<std::string, bool> result;
|
||||
|
||||
const auto append = [&result, &credits_per_hash_threshold](const std::vector<public_node> &nodes, bool white) {
|
||||
const auto append = [&result](const std::vector<public_node> &nodes, bool white) {
|
||||
for (const auto &node : nodes)
|
||||
{
|
||||
const bool rpc_payment_enabled = credits_per_hash_threshold > 0;
|
||||
const bool node_rpc_payment_enabled = node.rpc_credits_per_hash > 0;
|
||||
if (!node_rpc_payment_enabled ||
|
||||
(rpc_payment_enabled && node.rpc_credits_per_hash >= credits_per_hash_threshold))
|
||||
{
|
||||
result.insert(std::make_pair(node.host + ":" + std::to_string(node.rpc_port), white));
|
||||
}
|
||||
result.insert(std::make_pair(node.host + ":" + std::to_string(node.rpc_port), white));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -235,9 +222,6 @@ namespace cryptonote
|
||||
{
|
||||
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
|
||||
|
||||
constexpr const uint32_t credits_per_hash_threshold = 0;
|
||||
constexpr const bool rpc_payment_enabled = credits_per_hash_threshold != 0;
|
||||
|
||||
if (address.empty())
|
||||
{
|
||||
m_bootstrap_daemon.reset(nullptr);
|
||||
@@ -245,13 +229,13 @@ namespace cryptonote
|
||||
else if (address == "auto")
|
||||
{
|
||||
auto get_nodes = [this]() {
|
||||
return get_public_nodes(credits_per_hash_threshold);
|
||||
return get_public_nodes(0);
|
||||
};
|
||||
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled, m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
|
||||
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled, m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
|
||||
m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
|
||||
}
|
||||
|
||||
m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr;
|
||||
@@ -260,15 +244,12 @@ namespace cryptonote
|
||||
}
|
||||
core_rpc_server::~core_rpc_server()
|
||||
{
|
||||
if (m_rpc_payment)
|
||||
m_rpc_payment->store();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::init(
|
||||
const boost::program_options::variables_map& vm
|
||||
, const bool restricted
|
||||
, const std::string& port
|
||||
, bool allow_rpc_payment
|
||||
, const std::string& proxy
|
||||
)
|
||||
{
|
||||
@@ -295,45 +276,6 @@ namespace cryptonote
|
||||
}
|
||||
disable_rpc_ban = rpc_config->disable_rpc_ban;
|
||||
const std::string data_dir{command_line::get_arg(vm, cryptonote::arg_data_dir)};
|
||||
std::string address = command_line::get_arg(vm, arg_rpc_payment_address);
|
||||
if (!address.empty() && allow_rpc_payment)
|
||||
{
|
||||
if (!m_restricted && nettype() != FAKECHAIN)
|
||||
{
|
||||
MFATAL("RPC payment enabled, but server is not restricted, anyone can adjust their balance to bypass payment");
|
||||
return false;
|
||||
}
|
||||
cryptonote::address_parse_info info;
|
||||
if (!get_account_address_from_str(info, nettype(), address))
|
||||
{
|
||||
MFATAL("Invalid payment address: " << address);
|
||||
return false;
|
||||
}
|
||||
if (info.is_subaddress)
|
||||
{
|
||||
MFATAL("Payment address may not be a subaddress: " << address);
|
||||
return false;
|
||||
}
|
||||
uint64_t diff = command_line::get_arg(vm, arg_rpc_payment_difficulty);
|
||||
uint64_t credits = command_line::get_arg(vm, arg_rpc_payment_credits);
|
||||
if (diff == 0 || credits == 0)
|
||||
{
|
||||
MFATAL("Payments difficulty and/or payments credits are 0, but a payment address was given");
|
||||
return false;
|
||||
}
|
||||
m_rpc_payment_allow_free_loopback = command_line::get_arg(vm, arg_rpc_payment_allow_free_loopback);
|
||||
m_rpc_payment.reset(new rpc_payment(info.address, diff, credits));
|
||||
m_rpc_payment->load(data_dir);
|
||||
m_p2p.set_rpc_credits_per_hash(RPC_CREDITS_PER_HASH_SCALE * (credits / (float)diff));
|
||||
}
|
||||
|
||||
if (!m_rpc_payment)
|
||||
{
|
||||
uint32_t bind_ip;
|
||||
bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, bind_ip_str);
|
||||
if (ok & !epee::net_utils::is_ip_loopback(bind_ip))
|
||||
MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all.");
|
||||
}
|
||||
|
||||
if (!set_bootstrap_daemon(
|
||||
command_line::get_arg(vm, arg_bootstrap_daemon_address),
|
||||
@@ -349,9 +291,6 @@ namespace cryptonote
|
||||
if (rpc_config->login)
|
||||
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
|
||||
|
||||
if (m_rpc_payment)
|
||||
m_net_server.add_idle_handler([this](){ return m_rpc_payment->on_idle(); }, std::chrono::minutes{1});
|
||||
|
||||
bool store_ssl_key = !restricted && rpc_config->ssl_options && rpc_config->ssl_options.auth.certificate_path.empty();
|
||||
const auto ssl_base_path = (boost::filesystem::path{data_dir} / "rpc_ssl").string();
|
||||
const bool ssl_cert_file_exists = boost::filesystem::exists(ssl_base_path + ".crt");
|
||||
@@ -436,44 +375,6 @@ namespace cryptonote
|
||||
}
|
||||
return inited;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::check_payment(const std::string &client_message, uint64_t payment, const std::string &rpc, bool same_ts, std::string &message, uint64_t &credits, std::string &top_hash)
|
||||
{
|
||||
if (m_rpc_payment == NULL)
|
||||
{
|
||||
credits = 0;
|
||||
return true;
|
||||
}
|
||||
uint64_t height;
|
||||
crypto::hash hash;
|
||||
m_core.get_blockchain_top(height, hash);
|
||||
top_hash = epee::string_tools::pod_to_hex(hash);
|
||||
crypto::public_key client;
|
||||
uint64_t ts;
|
||||
#ifndef NDEBUG
|
||||
if (nettype() == TESTNET && client_message == "debug")
|
||||
{
|
||||
credits = 0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (!cryptonote::verify_rpc_payment_signature(client_message, client, ts))
|
||||
{
|
||||
credits = 0;
|
||||
message = "Client signature does not verify for " + rpc;
|
||||
return false;
|
||||
}
|
||||
if (!m_rpc_payment->pay(client, ts, payment, rpc, same_ts, credits))
|
||||
{
|
||||
message = CORE_RPC_STATUS_PAYMENT_REQUIRED;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#define CHECK_PAYMENT_BASE(req, res, payment, same_ts) do { if (!ctx) break; uint64_t P = (uint64_t)payment; if (P > 0 && !check_payment(req.client, P, tracker.rpc_name(), same_ts, res.status, res.credits, res.top_hash)){return true;} tracker.pay(P); } while(0)
|
||||
#define CHECK_PAYMENT(req, res, payment) CHECK_PAYMENT_BASE(req, res, payment, false)
|
||||
#define CHECK_PAYMENT_SAME_TS(req, res, payment) CHECK_PAYMENT_BASE(req, res, payment, true)
|
||||
#define CHECK_PAYMENT_MIN1(req, res, payment, same_ts) do { if (!ctx || (m_rpc_payment_allow_free_loopback && ctx->m_remote_address.is_loopback())) break; uint64_t P = (uint64_t)payment; if (P == 0) P = 1; if(!check_payment(req.client, P, tracker.rpc_name(), same_ts, res.status, res.credits, res.top_hash)){return true;} tracker.pay(P); } while(0)
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::check_core_ready()
|
||||
{
|
||||
@@ -539,8 +440,6 @@ namespace cryptonote
|
||||
return r;
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_GET_INFO, false);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
|
||||
crypto::hash top_hash;
|
||||
@@ -644,8 +543,6 @@ namespace cryptonote
|
||||
return use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r);
|
||||
}
|
||||
|
||||
CHECK_PAYMENT(req, res, 1);
|
||||
|
||||
res.daemon_time = (uint64_t)time(NULL);
|
||||
// Always set daemon time, and set it early rather than late, as delivering some incremental pool
|
||||
// info twice because of slightly overlapping time intervals is no problem, whereas producing gaps
|
||||
@@ -698,16 +595,6 @@ namespace cryptonote
|
||||
? std::min(req.max_block_count, (uint64_t)COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT)
|
||||
: COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT;
|
||||
|
||||
if (m_rpc_payment)
|
||||
{
|
||||
max_blocks = std::min((size_t)(res.credits / COST_PER_BLOCK), max_blocks);
|
||||
if (max_blocks == 0)
|
||||
{
|
||||
res.status = CORE_RPC_STATUS_PAYMENT_REQUIRED;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > > bs;
|
||||
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.top_block_hash, res.start_height, req.prune, !req.no_miner_tx, req.block_ids_exclusive, max_blocks, COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT))
|
||||
{
|
||||
@@ -716,8 +603,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_SAME_TS(req, res, bs.size() * COST_PER_BLOCK);
|
||||
|
||||
size_t ntxes = 0;
|
||||
res.blocks.reserve(bs.size());
|
||||
res.output_indices.reserve(bs.size());
|
||||
@@ -797,12 +682,6 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
res.added_pool_txs.clear();
|
||||
if (m_rpc_payment)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res,
|
||||
added_pool_txs.size() * COST_PER_TX +
|
||||
(res.remaining_added_pool_txids.size() + res.removed_pool_txids.size()) * COST_PER_POOL_HASH);
|
||||
}
|
||||
for (const auto &added_pool_tx: added_pool_txs)
|
||||
{
|
||||
COMMAND_RPC_GET_BLOCKS_FAST::pool_tx_info info;
|
||||
@@ -875,7 +754,6 @@ namespace cryptonote
|
||||
res.status = "Failed";
|
||||
res.blocks.clear();
|
||||
res.blocks.reserve(req.heights.size());
|
||||
CHECK_PAYMENT_MIN1(req, res, req.heights.size() * COST_PER_BLOCK, false);
|
||||
for (uint64_t height : req.heights)
|
||||
{
|
||||
block blk;
|
||||
@@ -907,8 +785,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN, "/gethashes.bin", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT(req, res, 1);
|
||||
|
||||
res.start_height = req.start_height;
|
||||
if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, res.m_block_ids, NULL, res.start_height, res.current_height, false))
|
||||
{
|
||||
@@ -917,8 +793,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_SAME_TS(req, res, res.m_block_ids.size() * COST_PER_BLOCK_HASH);
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
@@ -930,8 +804,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS_BIN>(invoke_http_mode::BIN, "/get_outs.bin", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, req.outputs.size() * COST_PER_OUT, false);
|
||||
|
||||
res.status = "Failed";
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
@@ -960,8 +832,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS>(invoke_http_mode::JON, "/get_outs", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, req.outputs.size() * COST_PER_OUT, false);
|
||||
|
||||
res.status = "Failed";
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
@@ -1007,8 +877,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES>(invoke_http_mode::BIN, "/get_o_indexes.bin", req, res, ok))
|
||||
return ok;
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_OUTPUT_INDEXES, false);
|
||||
|
||||
bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
|
||||
if(!r)
|
||||
{
|
||||
@@ -1036,8 +904,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
|
||||
|
||||
std::vector<crypto::hash> vh;
|
||||
for(const auto& tx_hex_str: req.txs_hashes)
|
||||
{
|
||||
@@ -1284,8 +1150,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
|
||||
|
||||
// parse key images from request
|
||||
std::vector<crypto::key_image> key_images;
|
||||
for(const auto& ki_hex_str: req.key_images)
|
||||
@@ -1387,8 +1251,6 @@ namespace cryptonote
|
||||
CHECK_CORE_READY();
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false);
|
||||
|
||||
std::string tx_blob;
|
||||
if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob))
|
||||
{
|
||||
@@ -1721,8 +1583,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL>(invoke_http_mode::JON, "/get_transaction_pool", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT(req, res, 1);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
const bool allow_sensitive = !request_has_rpc_origin || !restricted;
|
||||
@@ -1730,7 +1590,6 @@ namespace cryptonote
|
||||
size_t n_txes = m_core.get_pool_transactions_count(allow_sensitive);
|
||||
if (n_txes > 0)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res, n_txes * COST_PER_TX);
|
||||
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, allow_sensitive);
|
||||
for (tx_info& txi : res.transactions)
|
||||
txi.tx_blob = epee::string_tools::buff_to_hex_nodelimer(txi.tx_blob);
|
||||
@@ -1747,8 +1606,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT(req, res, 1);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
const bool allow_sensitive = !request_has_rpc_origin || !restricted;
|
||||
@@ -1756,7 +1613,6 @@ namespace cryptonote
|
||||
size_t n_txes = m_core.get_pool_transactions_count(allow_sensitive);
|
||||
if (n_txes > 0)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res, n_txes * COST_PER_POOL_HASH);
|
||||
m_core.get_pool_transaction_hashes(res.tx_hashes, allow_sensitive);
|
||||
}
|
||||
|
||||
@@ -1771,8 +1627,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT(req, res, 1);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
const bool allow_sensitive = !request_has_rpc_origin || !restricted;
|
||||
@@ -1780,7 +1634,6 @@ namespace cryptonote
|
||||
size_t n_txes = m_core.get_pool_transactions_count(allow_sensitive);
|
||||
if (n_txes > 0)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res, n_txes * COST_PER_POOL_HASH);
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
m_core.get_pool_transaction_hashes(tx_hashes, allow_sensitive);
|
||||
res.tx_hashes.reserve(tx_hashes.size());
|
||||
@@ -1799,8 +1652,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_STATS>(invoke_http_mode::JON, "/get_transaction_pool_stats", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_POOL_STATS, false);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
m_core.get_pool_transaction_stats(res.pool_stats, !request_has_rpc_origin || !restricted);
|
||||
@@ -2561,7 +2412,6 @@ namespace cryptonote
|
||||
return r;
|
||||
|
||||
CHECK_CORE_READY();
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
|
||||
uint64_t last_block_height;
|
||||
crypto::hash last_block_hash;
|
||||
m_core.get_blockchain_top(last_block_height, last_block_hash);
|
||||
@@ -2592,8 +2442,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC, "getblockheaderbyhash", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
if (restricted && req.hashes.size() > RESTRICTED_BLOCK_COUNT)
|
||||
{
|
||||
@@ -2676,7 +2524,6 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false);
|
||||
for (uint64_t h = req.start_height; h <= req.end_height; ++h)
|
||||
{
|
||||
crypto::hash block_hash = m_core.get_block_id_by_height(h);
|
||||
@@ -2727,7 +2574,6 @@ namespace cryptonote
|
||||
error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1);
|
||||
return false;
|
||||
}
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
|
||||
crypto::hash block_hash = m_core.get_block_id_by_height(req.height);
|
||||
block blk;
|
||||
bool have_block = m_core.get_block_by_hash(block_hash, blk);
|
||||
@@ -2756,8 +2602,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK>(invoke_http_mode::JON_RPC, "getblock", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK, false);
|
||||
|
||||
crypto::hash block_hash;
|
||||
if (!req.hash.empty())
|
||||
{
|
||||
@@ -2843,7 +2687,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_HARD_FORK_INFO>(invoke_http_mode::JON_RPC, "hard_fork_info", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT(req, res, COST_PER_HARD_FORK_INFO);
|
||||
const Blockchain &blockchain = m_core.get_blockchain_storage();
|
||||
uint8_t version = req.version > 0 ? req.version : blockchain.get_next_hard_fork_version();
|
||||
res.version = blockchain.get_current_hard_fork_version();
|
||||
@@ -3040,9 +2883,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t cost = req.amounts.empty() ? COST_PER_FULL_OUTPUT_HISTOGRAM : (COST_PER_OUTPUT_HISTOGRAM * amounts);
|
||||
CHECK_PAYMENT_MIN1(req, res, cost, false);
|
||||
|
||||
if (restricted && req.recent_cutoff > 0 && req.recent_cutoff < (uint64_t)time(NULL) - OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION)
|
||||
{
|
||||
res.status = "Recent cutoff is too old";
|
||||
@@ -3098,7 +2938,6 @@ namespace cryptonote
|
||||
res.status = "requested range exceeds blockchain height";
|
||||
return true;
|
||||
}
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_COINBASE_TX_SUM_BLOCK * req.count, false);
|
||||
std::pair<boost::multiprecision::uint128_t, boost::multiprecision::uint128_t> amounts = m_core.get_coinbase_tx_sum(req.height, req.count);
|
||||
store_128(amounts.first, res.emission_amount, res.wide_emission_amount, res.emission_amount_top64);
|
||||
store_128(amounts.second, res.fee_amount, res.wide_fee_amount, res.fee_amount_top64);
|
||||
@@ -3113,8 +2952,6 @@ namespace cryptonote
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BASE_FEE_ESTIMATE>(invoke_http_mode::JON_RPC, "get_fee_estimate", req, res, r))
|
||||
return r;
|
||||
|
||||
CHECK_PAYMENT(req, res, COST_PER_FEE_ESTIMATE);
|
||||
|
||||
{
|
||||
m_core.get_blockchain_storage().get_dynamic_base_fee_estimate_2021_scaling(req.grace_blocks, res.fees);
|
||||
res.fee = res.fees[0];
|
||||
@@ -3348,7 +3185,6 @@ namespace cryptonote
|
||||
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, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(relay_tx);
|
||||
CHECK_PAYMENT_MIN1(req, res, req.txids.size() * COST_PER_TX_RELAY, false);
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
|
||||
@@ -3400,7 +3236,6 @@ namespace cryptonote
|
||||
bool core_rpc_server::on_sync_info(const COMMAND_RPC_SYNC_INFO::request& req, COMMAND_RPC_SYNC_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(sync_info);
|
||||
CHECK_PAYMENT(req, res, COST_PER_SYNC_INFO);
|
||||
|
||||
crypto::hash top_hash;
|
||||
m_core.get_blockchain_top(res.height, top_hash);
|
||||
@@ -3429,8 +3264,6 @@ namespace cryptonote
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG>(invoke_http_mode::JON_RPC, "get_txpool_backlog", req, res, r))
|
||||
return r;
|
||||
size_t n_txes = m_core.get_pool_transactions_count();
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_POOL_STATS * n_txes, false);
|
||||
|
||||
if (!m_core.get_txpool_backlog(res.backlog))
|
||||
{
|
||||
@@ -3458,11 +3291,6 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t n_0 = 0, n_non0 = 0;
|
||||
for (uint64_t amount: req.amounts)
|
||||
if (amount) ++n_non0; else ++n_0;
|
||||
CHECK_PAYMENT_MIN1(req, res, n_0 * COST_PER_OUTPUT_DISTRIBUTION_0 + n_non0 * COST_PER_OUTPUT_DISTRIBUTION, false);
|
||||
|
||||
try
|
||||
{
|
||||
// 0 is placeholder for the whole chain
|
||||
@@ -3506,11 +3334,6 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t n_0 = 0, n_non0 = 0;
|
||||
for (uint64_t amount: req.amounts)
|
||||
if (amount) ++n_non0; else ++n_0;
|
||||
CHECK_PAYMENT_MIN1(req, res, n_0 * COST_PER_OUTPUT_DISTRIBUTION_0 + n_non0 * COST_PER_OUTPUT_DISTRIBUTION, false);
|
||||
|
||||
res.status = "Failed";
|
||||
|
||||
if (!req.binary)
|
||||
@@ -3569,70 +3392,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_rpc_access_info(const COMMAND_RPC_ACCESS_INFO::request& req, COMMAND_RPC_ACCESS_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(rpc_access_info);
|
||||
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ACCESS_INFO>(invoke_http_mode::JON_RPC, "rpc_access_info", req, res, r))
|
||||
return r;
|
||||
|
||||
// if RPC payment is not enabled
|
||||
if (m_rpc_payment == NULL)
|
||||
{
|
||||
res.diff = 0;
|
||||
res.credits_per_hash_found = 0;
|
||||
res.credits = 0;
|
||||
res.height = 0;
|
||||
res.seed_height = 0;
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
crypto::public_key client;
|
||||
uint64_t ts;
|
||||
if (!cryptonote::verify_rpc_payment_signature(req.client, client, ts))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INVALID_CLIENT;
|
||||
error_resp.message = "Invalid client ID";
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash top_hash;
|
||||
m_core.get_blockchain_top(res.height, top_hash);
|
||||
++res.height;
|
||||
cryptonote::blobdata hashing_blob;
|
||||
crypto::hash seed_hash, next_seed_hash;
|
||||
if (!m_rpc_payment->get_info(client, [&](const cryptonote::blobdata &extra_nonce, cryptonote::block &b, uint64_t &seed_height, crypto::hash &seed_hash)->bool{
|
||||
cryptonote::difficulty_type difficulty;
|
||||
uint64_t height, expected_reward, cumulative_weight;
|
||||
size_t reserved_offset;
|
||||
if (!get_block_template(m_rpc_payment->get_payment_address(), NULL, extra_nonce, reserved_offset, difficulty, height, expected_reward, cumulative_weight, b, seed_height, seed_hash, next_seed_hash, error_resp))
|
||||
return false;
|
||||
return true;
|
||||
}, hashing_blob, res.seed_height, seed_hash, top_hash, res.diff, res.credits_per_hash_found, res.credits, res.cookie))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (hashing_blob.empty())
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
|
||||
error_resp.message = "Invalid hashing blob";
|
||||
return false;
|
||||
}
|
||||
res.hashing_blob = epee::string_tools::buff_to_hex_nodelimer(hashing_blob);
|
||||
res.top_hash = epee::string_tools::pod_to_hex(top_hash);
|
||||
if (hashing_blob[0] >= RX_BLOCK_VERSION)
|
||||
{
|
||||
res.seed_hash = string_tools::pod_to_hex(seed_hash);
|
||||
if (seed_hash != next_seed_hash)
|
||||
res.next_seed_hash = string_tools::pod_to_hex(next_seed_hash);
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_flush_cache(const COMMAND_RPC_FLUSH_CACHE::request& req, COMMAND_RPC_FLUSH_CACHE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(flush_cache);
|
||||
@@ -3718,181 +3477,6 @@ namespace cryptonote
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_rpc_access_submit_nonce(const COMMAND_RPC_ACCESS_SUBMIT_NONCE::request& req, COMMAND_RPC_ACCESS_SUBMIT_NONCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(rpc_access_submit_nonce);
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ACCESS_SUBMIT_NONCE>(invoke_http_mode::JON_RPC, "rpc_access_submit_nonce", req, res, r))
|
||||
return r;
|
||||
|
||||
// if RPC payment is not enabled
|
||||
if (m_rpc_payment == NULL)
|
||||
{
|
||||
res.status = "Payment not necessary";
|
||||
return true;
|
||||
}
|
||||
|
||||
crypto::public_key client;
|
||||
uint64_t ts;
|
||||
if (!cryptonote::verify_rpc_payment_signature(req.client, client, ts))
|
||||
{
|
||||
res.credits = 0;
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INVALID_CLIENT;
|
||||
error_resp.message = "Invalid client ID";
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash hash;
|
||||
cryptonote::block block;
|
||||
crypto::hash top_hash;
|
||||
uint64_t height;
|
||||
bool stale;
|
||||
m_core.get_blockchain_top(height, top_hash);
|
||||
if (!m_rpc_payment->submit_nonce(client, req.nonce, top_hash, error_resp.code, error_resp.message, res.credits, hash, block, req.cookie, stale))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stale)
|
||||
{
|
||||
// it might be a valid block!
|
||||
const difficulty_type current_difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
|
||||
if (check_hash(hash, current_difficulty))
|
||||
{
|
||||
MINFO("This payment meets the current network difficulty");
|
||||
block_verification_context bvc;
|
||||
if(m_core.handle_block_found(block, bvc))
|
||||
MGINFO_GREEN("Block found by RPC user at height " << get_block_height(block) << ": " <<
|
||||
print_money(cryptonote::get_outs_money_amount(block.miner_tx)));
|
||||
else
|
||||
MERROR("Seemingly valid block was not accepted");
|
||||
}
|
||||
}
|
||||
|
||||
m_core.get_blockchain_top(height, top_hash);
|
||||
res.top_hash = epee::string_tools::pod_to_hex(top_hash);
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_rpc_access_pay(const COMMAND_RPC_ACCESS_PAY::request& req, COMMAND_RPC_ACCESS_PAY::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(rpc_access_pay);
|
||||
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ACCESS_PAY>(invoke_http_mode::JON_RPC, "rpc_access_pay", req, res, r))
|
||||
return r;
|
||||
|
||||
// if RPC payment is not enabled
|
||||
if (m_rpc_payment == NULL)
|
||||
{
|
||||
res.status = "Payment not necessary";
|
||||
return true;
|
||||
}
|
||||
|
||||
crypto::public_key client;
|
||||
uint64_t ts;
|
||||
if (!cryptonote::verify_rpc_payment_signature(req.client, client, ts))
|
||||
{
|
||||
res.credits = 0;
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INVALID_CLIENT;
|
||||
error_resp.message = "Invalid client ID";
|
||||
return false;
|
||||
}
|
||||
|
||||
RPCTracker ext_tracker(("external:" + req.paying_for).c_str(), PERF_TIMER_NAME(rpc_access_pay));
|
||||
if (!check_payment(req.client, req.payment, req.paying_for, false, res.status, res.credits, res.top_hash))
|
||||
return true;
|
||||
ext_tracker.pay(req.payment);
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_rpc_access_tracking(const COMMAND_RPC_ACCESS_TRACKING::request& req, COMMAND_RPC_ACCESS_TRACKING::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(rpc_access_tracking);
|
||||
|
||||
if (req.clear)
|
||||
{
|
||||
RPCTracker::clear();
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto data = RPCTracker::data();
|
||||
for (const auto &d: data)
|
||||
{
|
||||
res.data.resize(res.data.size() + 1);
|
||||
res.data.back().rpc = d.first;
|
||||
res.data.back().count = d.second.count;
|
||||
res.data.back().time = d.second.time;
|
||||
res.data.back().credits = d.second.credits;
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_rpc_access_data(const COMMAND_RPC_ACCESS_DATA::request& req, COMMAND_RPC_ACCESS_DATA::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(rpc_access_data);
|
||||
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ACCESS_DATA>(invoke_http_mode::JON_RPC, "rpc_access_data", req, res, r))
|
||||
return r;
|
||||
|
||||
if (!m_rpc_payment)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_PAYMENTS_NOT_ENABLED;
|
||||
error_resp.message = "Payments not enabled";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_rpc_payment->foreach([&](const crypto::public_key &client, const rpc_payment::client_info &info){
|
||||
res.entries.push_back({
|
||||
epee::string_tools::pod_to_hex(client), info.credits, std::max(info.last_request_timestamp / 1000000, info.update_time),
|
||||
info.credits_total, info.credits_used, info.nonces_good, info.nonces_stale, info.nonces_bad, info.nonces_dupe
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
res.hashrate = m_rpc_payment->get_hashes(600) / 600;
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_rpc_access_account(const COMMAND_RPC_ACCESS_ACCOUNT::request& req, COMMAND_RPC_ACCESS_ACCOUNT::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
|
||||
{
|
||||
RPC_TRACKER(rpc_access_account);
|
||||
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ACCESS_ACCOUNT>(invoke_http_mode::JON_RPC, "rpc_access_account", req, res, r))
|
||||
return r;
|
||||
|
||||
if (!m_rpc_payment)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_PAYMENTS_NOT_ENABLED;
|
||||
error_resp.message = "Payments not enabled";
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::public_key client;
|
||||
if (!epee::string_tools::hex_to_pod(req.client.substr(0, 2 * sizeof(client)), client))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INVALID_CLIENT;
|
||||
error_resp.message = "Invalid client ID";
|
||||
return false;
|
||||
}
|
||||
|
||||
res.credits = m_rpc_payment->balance(client, req.delta_balance);
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
const command_line::arg_descriptor<std::string, false, true, 2> core_rpc_server::arg_rpc_bind_port = {
|
||||
"rpc-bind-port"
|
||||
, "Port for RPC server"
|
||||
@@ -3938,30 +3522,6 @@ namespace cryptonote
|
||||
, ""
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_payment_address = {
|
||||
"rpc-payment-address"
|
||||
, "Restrict RPC to clients sending micropayment to this address"
|
||||
, ""
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<uint64_t> core_rpc_server::arg_rpc_payment_difficulty = {
|
||||
"rpc-payment-difficulty"
|
||||
, "Restrict RPC to clients sending micropayment at this difficulty"
|
||||
, DEFAULT_PAYMENT_DIFFICULTY
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<uint64_t> core_rpc_server::arg_rpc_payment_credits = {
|
||||
"rpc-payment-credits"
|
||||
, "Restrict RPC to clients sending micropayment, yields that many credits per payment"
|
||||
, DEFAULT_PAYMENT_CREDITS_PER_HASH
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_payment_allow_free_loopback = {
|
||||
"rpc-payment-allow-free-loopback"
|
||||
, "Allow free access from the loopback address (ie, the local host)"
|
||||
, false
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_max_connections_per_public_ip = {
|
||||
"rpc-max-connections-per-public-ip"
|
||||
, "Max RPC connections per public IP permitted"
|
||||
|
||||
Reference in New Issue
Block a user