aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
authorluigi1111 <luigi1111w@gmail.com>2019-10-25 13:38:21 -0500
committerluigi1111 <luigi1111w@gmail.com>2019-10-25 13:38:21 -0500
commit960c2158010d30a375207310a36a7a942b9285d2 (patch)
tree46d25ec0db661fd62fd1a683dea3b1ecbf620089 /src/rpc
parentMerge pull request #6002 (diff)
parentsimplewallet: add public_nodes command (diff)
downloadmonero-960c2158010d30a375207310a36a7a942b9285d2.tar.xz
Merge pull request #5357
b3a9a4d add a quick early out to get_blocks.bin when up to date (moneromooo-monero) 2899379 daemon, wallet: new pay for RPC use system (moneromooo-monero) ffa4602 simplewallet: add public_nodes command (moneromooo-monero)
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/CMakeLists.txt11
-rw-r--r--src/rpc/core_rpc_server.cpp773
-rw-r--r--src/rpc/core_rpc_server.h23
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h804
-rw-r--r--src/rpc/core_rpc_server_error_codes.h29
-rw-r--r--src/rpc/message_data_structs.h1
-rw-r--r--src/rpc/rpc_payment.cpp402
-rw-r--r--src/rpc/rpc_payment.h146
-rw-r--r--src/rpc/rpc_payment_costs.h50
-rw-r--r--src/rpc/rpc_payment_signature.cpp107
-rw-r--r--src/rpc/rpc_payment_signature.h39
11 files changed, 1950 insertions, 435 deletions
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index 116e7f568..ebb1e767f 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -29,12 +29,14 @@
include_directories(SYSTEM ${ZMQ_INCLUDE_PATH})
set(rpc_base_sources
- rpc_args.cpp)
+ rpc_args.cpp
+ rpc_payment_signature.cpp
+ rpc_handler.cpp)
set(rpc_sources
bootstrap_daemon.cpp
core_rpc_server.cpp
- rpc_handler.cpp
+ rpc_payment.cpp
instanciations)
set(daemon_messages_sources
@@ -47,7 +49,9 @@ set(daemon_rpc_server_sources
set(rpc_base_headers
- rpc_args.h)
+ rpc_args.h
+ rpc_payment_signature.h
+ rpc_handler.h)
set(rpc_headers
rpc_handler.h)
@@ -58,6 +62,7 @@ set(daemon_rpc_server_headers)
set(rpc_daemon_private_headers
bootstrap_daemon.h
core_rpc_server.h
+ rpc_payment.h
core_rpc_server_commands_defs.h
core_rpc_server_error_codes.h)
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index dfc4d4cf3..8882df5d7 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -39,6 +39,7 @@ using namespace epee;
#include "common/download.h"
#include "common/util.h"
#include "common/perf_timer.h"
+#include "int-util.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
@@ -49,6 +50,8 @@ 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"
@@ -61,8 +64,50 @@ using namespace epee;
#define OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION (3 * 86400) // 3 days max, the wallet requests 1.8 days
+#define DEFAULT_PAYMENT_DIFFICULTY 1000
+#define DEFAULT_PAYMENT_CREDITS_PER_HASH 100
+
+#define RPC_TRACKER(rpc) \
+ PERF_TIMER(rpc); \
+ RPCTracker tracker(#rpc, PERF_TIMER_NAME(rpc))
+
namespace
{
+ class RPCTracker
+ {
+ public:
+ struct entry_t
+ {
+ uint64_t count;
+ uint64_t time;
+ uint64_t credits;
+ };
+
+ RPCTracker(const char *rpc, tools::LoggingPerformanceTimer &timer): rpc(rpc), timer(timer) {
+ }
+ ~RPCTracker() {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ auto &e = tracker[rpc];
+ ++e.count;
+ e.time += timer.value();
+ }
+ void pay(uint64_t amount) {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ auto &e = tracker[rpc];
+ e.credits += amount;
+ }
+ const std::string &rpc_name() const { return rpc; }
+ static void clear() { boost::unique_lock<boost::mutex> lock(mutex); tracker.clear(); }
+ static std::unordered_map<std::string, entry_t> data() { boost::unique_lock<boost::mutex> lock(mutex); return tracker; }
+ private:
+ std::string rpc;
+ tools::LoggingPerformanceTimer &timer;
+ static boost::mutex mutex;
+ static std::unordered_map<std::string, entry_t> tracker;
+ };
+ boost::mutex RPCTracker::mutex;
+ std::unordered_map<std::string, RPCTracker::entry_t> RPCTracker::tracker;
+
void add_reason(std::string &reasons, const char *reason)
{
if (!reasons.empty())
@@ -95,6 +140,9 @@ namespace cryptonote
command_line::add_arg(desc, arg_bootstrap_daemon_address);
command_line::add_arg(desc, arg_bootstrap_daemon_login);
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);
}
//------------------------------------------------------------------------------------------------------------------------------
core_rpc_server::core_rpc_server(
@@ -173,6 +221,11 @@ namespace cryptonote
return true;
}
+ 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
@@ -188,6 +241,45 @@ namespace cryptonote
if (!rpc_config)
return false;
+ std::string address = command_line::get_arg(vm, arg_rpc_payment_address);
+ if (!address.empty())
+ {
+ if (!m_restricted && nettype() != FAKECHAIN)
+ {
+ MERROR("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))
+ {
+ MERROR("Invalid payment address: " << address);
+ return false;
+ }
+ if (info.is_subaddress)
+ {
+ MERROR("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)
+ {
+ MERROR("Payments difficulty and/or payments credits are 0, but a payment address was given");
+ return false;
+ }
+ m_rpc_payment.reset(new rpc_payment(info.address, diff, credits));
+ m_rpc_payment->load(command_line::get_arg(vm, cryptonote::arg_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, rpc_config->bind_ip);
+ 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),
command_line::get_arg(vm, arg_bootstrap_daemon_login)))
{
@@ -200,6 +292,9 @@ 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(); }, 60 * 1000);
+
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
rng, std::move(port), std::move(rpc_config->bind_ip),
@@ -208,6 +303,45 @@ namespace cryptonote
);
}
//------------------------------------------------------------------------------------------------------------------------------
+ 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;
+ }
+ crypto::public_key local_client;
+ 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) 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()
{
if(!m_p2p.get_payload_object().is_synchronized())
@@ -239,7 +373,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_height);
+ RPC_TRACKER(get_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON, "/getheight", req, res, r))
return r;
@@ -254,7 +388,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_info);
+ RPC_TRACKER(get_info);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON, "/getinfo", req, res, r))
{
@@ -272,6 +406,8 @@ namespace cryptonote
return r;
}
+ CHECK_PAYMENT_MIN1(req, res, COST_PER_GET_INFO, false);
+
const bool restricted = m_restricted && ctx;
crypto::hash top_hash;
@@ -330,7 +466,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request& req, COMMAND_RPC_GET_NET_STATS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_net_stats);
+ RPC_TRACKER(get_net_stats);
// No bootstrap daemon check: Only ever get stats about local server
res.start_time = (uint64_t)m_core.get_start_time();
{
@@ -357,20 +493,51 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_blocks);
+ RPC_TRACKER(get_blocks);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r))
return r;
- std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > > bs;
+ CHECK_PAYMENT(req, res, 1);
+
+ // quick check for noop
+ if (!req.block_ids.empty())
+ {
+ uint64_t last_block_height;
+ crypto::hash last_block_hash;
+ m_core.get_blockchain_top(last_block_height, last_block_hash);
+ if (last_block_hash == req.block_ids.front())
+ {
+ res.start_height = 0;
+ res.current_height = m_core.get_current_blockchain_height();
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ }
- if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, req.prune, !req.no_miner_tx, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
+ size_t max_blocks = COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT;
+ if (m_rpc_payment)
+ {
+ max_blocks = res.credits / COST_PER_BLOCK;
+ if (max_blocks > COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT)
+ max_blocks = COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT;
+ if (max_blocks == 0)
+ {
+ res.status = CORE_RPC_STATUS_PAYMENT_REQUIRED;
+ return false;
+ }
+ }
+
+ 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.start_height, req.prune, !req.no_miner_tx, max_blocks))
{
res.status = "Failed";
add_host_fail(ctx);
return false;
}
+ CHECK_PAYMENT_SAME_TS(req, res, bs.size() * COST_PER_BLOCK);
+
size_t pruned_size = 0, unpruned_size = 0, ntxes = 0;
res.blocks.reserve(bs.size());
res.output_indices.reserve(bs.size());
@@ -422,7 +589,7 @@ namespace cryptonote
}
bool core_rpc_server::on_get_alt_blocks_hashes(const COMMAND_RPC_GET_ALT_BLOCKS_HASHES::request& req, COMMAND_RPC_GET_ALT_BLOCKS_HASHES::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_alt_blocks_hashes);
+ RPC_TRACKER(get_alt_blocks_hashes);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_ALT_BLOCKS_HASHES>(invoke_http_mode::JON, "/get_alt_blocks_hashes", req, res, r))
return r;
@@ -449,7 +616,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_blocks_by_height);
+ RPC_TRACKER(get_blocks_by_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
return r;
@@ -457,6 +624,7 @@ 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;
@@ -483,11 +651,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_hashes);
+ RPC_TRACKER(get_hashes);
bool r;
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))
{
@@ -496,17 +666,21 @@ namespace cryptonote
return false;
}
+ CHECK_PAYMENT_SAME_TS(req, res, res.m_block_ids.size() * COST_PER_BLOCK_HASH);
+
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_outs_bin);
+ RPC_TRACKER(get_outs_bin);
bool r;
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;
@@ -530,11 +704,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_outs);
+ RPC_TRACKER(get_outs);
bool r;
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;
@@ -574,11 +750,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_indexes);
+ RPC_TRACKER(get_indexes);
bool ok;
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)
{
@@ -592,11 +770,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_transactions);
+ RPC_TRACKER(get_transactions);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
return ok;
+ 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)
{
@@ -818,13 +998,16 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_is_key_image_spent);
+ RPC_TRACKER(is_key_image_spent);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
return ok;
+ CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
+
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
+
std::vector<crypto::key_image> key_images;
for(const auto& ki_hex_str: req.key_images)
{
@@ -887,12 +1070,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_send_raw_tx);
+ RPC_TRACKER(send_raw_tx);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok))
return ok;
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))
@@ -966,7 +1150,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_start_mining);
+ RPC_TRACKER(start_mining);
CHECK_CORE_READY();
cryptonote::address_parse_info info;
if(!get_account_address_from_str(info, nettype(), req.miner_address))
@@ -1017,7 +1201,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_stop_mining);
+ RPC_TRACKER(stop_mining);
cryptonote::miner &miner= m_core.get_miner();
if(!miner.is_mining())
{
@@ -1037,7 +1221,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_mining_status(const COMMAND_RPC_MINING_STATUS::request& req, COMMAND_RPC_MINING_STATUS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_mining_status);
+ RPC_TRACKER(mining_status);
const miner& lMiner = m_core.get_miner();
res.active = lMiner.is_mining();
@@ -1078,7 +1262,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_save_bc);
+ RPC_TRACKER(save_bc);
if( !m_core.get_blockchain_storage().store_blockchain() )
{
res.status = "Error while storing blockchain";
@@ -1090,7 +1274,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_peer_list);
+ RPC_TRACKER(get_peer_list);
std::vector<nodetool::peerlist_entry> white_list;
std::vector<nodetool::peerlist_entry> gray_list;
@@ -1107,24 +1291,24 @@ namespace cryptonote
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
- entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
+ entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
else if (entry.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(),
- entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
+ entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
else
- res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
+ res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
}
for (auto & entry : gray_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
- entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
+ entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
else if (entry.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(),
- entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
+ entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
else
- res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
+ res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
}
res.status = CORE_RPC_STATUS_OK;
@@ -1133,7 +1317,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_public_nodes(const COMMAND_RPC_GET_PUBLIC_NODES::request& req, COMMAND_RPC_GET_PUBLIC_NODES::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_public_nodes);
+ RPC_TRACKER(get_public_nodes);
COMMAND_RPC_GET_PEER_LIST::response peer_list_res;
const bool success = on_get_peer_list(COMMAND_RPC_GET_PEER_LIST::request(), peer_list_res, ctx);
@@ -1172,7 +1356,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_set_log_hash_rate);
+ RPC_TRACKER(set_log_hash_rate);
if(m_core.get_miner().is_mining())
{
m_core.get_miner().do_print_hashrate(req.visible);
@@ -1187,7 +1371,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_set_log_level);
+ RPC_TRACKER(set_log_level);
if (req.level < 0 || req.level > 4)
{
res.status = "Error: log level not valid";
@@ -1200,7 +1384,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_set_log_categories);
+ RPC_TRACKER(set_log_categories);
mlog_set_log(req.categories.c_str());
res.categories = mlog_get_categories();
res.status = CORE_RPC_STATUS_OK;
@@ -1209,62 +1393,92 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_transaction_pool);
+ RPC_TRACKER(get_transaction_pool);
bool r;
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;
- m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !restricted);
- for (tx_info& txi : res.transactions)
- txi.tx_blob = epee::string_tools::buff_to_hex_nodelimer(txi.tx_blob);
+
+ size_t n_txes = m_core.get_pool_transactions_count();
+ 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, !request_has_rpc_origin || !restricted);
+ for (tx_info& txi : res.transactions)
+ txi.tx_blob = epee::string_tools::buff_to_hex_nodelimer(txi.tx_blob);
+ }
+
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_transaction_pool_hashes);
+ RPC_TRACKER(get_transaction_pool_hashes);
bool r;
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;
- m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !restricted);
+
+ size_t n_txes = m_core.get_pool_transactions_count();
+ 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, !request_has_rpc_origin || !restricted);
+ }
+
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_transaction_pool_hashes);
+ RPC_TRACKER(get_transaction_pool_hashes);
bool r;
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;
- std::vector<crypto::hash> tx_hashes;
- m_core.get_pool_transaction_hashes(tx_hashes, !request_has_rpc_origin || !restricted);
- res.tx_hashes.reserve(tx_hashes.size());
- for (const crypto::hash &tx_hash: tx_hashes)
- res.tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash));
+
+ size_t n_txes = m_core.get_pool_transactions_count();
+ 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, !request_has_rpc_origin || !restricted);
+ res.tx_hashes.reserve(tx_hashes.size());
+ for (const crypto::hash &tx_hash: tx_hashes)
+ res.tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash));
+ }
+
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_transaction_pool_stats);
+ RPC_TRACKER(get_transaction_pool_stats);
bool r;
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);
+
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -1293,7 +1507,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_stop_daemon);
+ RPC_TRACKER(stop_daemon);
// FIXME: replace back to original m_p2p.send_stop_signal() after
// investigating why that isn't working quite right.
m_p2p.send_stop_signal();
@@ -1303,7 +1517,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_getblockcount);
+ RPC_TRACKER(getblockcount);
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
@@ -1319,7 +1533,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_getblockhash);
+ RPC_TRACKER(getblockhash);
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
@@ -1361,9 +1575,65 @@ namespace cryptonote
return 0;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::get_block_template(const account_public_address &address, const crypto::hash *prev_block, const cryptonote::blobdata &extra_nonce, size_t &reserved_offset, cryptonote::difficulty_type &difficulty, uint64_t &height, uint64_t &expected_reward, block &b, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, epee::json_rpc::error &error_resp)
+ {
+ b = boost::value_initialized<cryptonote::block>();
+ if(!m_core.get_block_template(b, prev_block, address, difficulty, height, expected_reward, extra_nonce))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Internal error: failed to create block template";
+ LOG_ERROR("Failed to create block template");
+ return false;
+ }
+ blobdata block_blob = t_serializable_object_to_blob(b);
+ crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
+ if(tx_pub_key == crypto::null_pkey)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Internal error: failed to create block template";
+ LOG_ERROR("Failed to get tx pub key in coinbase extra");
+ return false;
+ }
+
+ if (b.major_version >= RX_BLOCK_VERSION)
+ {
+ uint64_t next_height;
+ crypto::rx_seedheights(height, &seed_height, &next_height);
+ seed_hash = m_core.get_block_id_by_height(seed_height);
+ if (next_height != seed_height)
+ next_seed_hash = m_core.get_block_id_by_height(next_height);
+ else
+ next_seed_hash = seed_hash;
+ }
+
+ if (extra_nonce.empty())
+ {
+ reserved_offset = 0;
+ return true;
+ }
+
+ reserved_offset = slow_memmem((void*)block_blob.data(), block_blob.size(), &tx_pub_key, sizeof(tx_pub_key));
+ if(!reserved_offset)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Internal error: failed to create block template";
+ LOG_ERROR("Failed to find tx pub key in blockblob");
+ return false;
+ }
+ reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
+ if(reserved_offset + extra_nonce.size() > block_blob.size())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Internal error: failed to create block template";
+ LOG_ERROR("Failed to calculate offset for ");
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_getblocktemplate);
+ RPC_TRACKER(getblocktemplate);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GETBLOCKTEMPLATE>(invoke_http_mode::JON_RPC, "getblocktemplate", req, res, r))
return r;
@@ -1413,6 +1683,7 @@ namespace cryptonote
block b;
cryptonote::blobdata blob_reserve;
+ size_t reserved_offset;
if(!req.extra_nonce.empty())
{
if(!string_tools::parse_hexstr_to_binbuff(req.extra_nonce, blob_reserve))
@@ -1435,54 +1706,20 @@ namespace cryptonote
return false;
}
}
- if(!m_core.get_block_template(b, req.prev_block.empty() ? NULL : &prev_block, info.address, wdiff, res.height, res.expected_reward, blob_reserve))
- {
- error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
- error_resp.message = "Internal error: failed to create block template";
- LOG_ERROR("Failed to create block template");
+ uint64_t seed_height;
+ crypto::hash seed_hash, next_seed_hash;
+ if (!get_block_template(info.address, req.prev_block.empty() ? NULL : &prev_block, blob_reserve, reserved_offset, wdiff, res.height, res.expected_reward, b, res.seed_height, seed_hash, next_seed_hash, error_resp))
return false;
- }
if (b.major_version >= RX_BLOCK_VERSION)
{
- uint64_t seed_height, next_height;
- crypto::hash seed_hash;
- crypto::rx_seedheights(res.height, &seed_height, &next_height);
- seed_hash = m_core.get_block_id_by_height(seed_height);
res.seed_hash = string_tools::pod_to_hex(seed_hash);
- if (next_height != seed_height) {
- seed_hash = m_core.get_block_id_by_height(next_height);
- res.next_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.reserved_offset = reserved_offset;
store_difficulty(wdiff, res.difficulty, res.wide_difficulty, res.difficulty_top64);
blobdata block_blob = t_serializable_object_to_blob(b);
- crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
- if(tx_pub_key == crypto::null_pkey)
- {
- error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
- error_resp.message = "Internal error: failed to create block template";
- LOG_ERROR("Failed to get tx pub key in coinbase extra");
- return false;
- }
- res.reserved_offset = slow_memmem((void*)block_blob.data(), block_blob.size(), &tx_pub_key, sizeof(tx_pub_key));
- if(!res.reserved_offset)
- {
- error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
- error_resp.message = "Internal error: failed to create block template";
- LOG_ERROR("Failed to find tx pub key in blockblob");
- return false;
- }
- if (req.reserve_size)
- res.reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
- else
- res.reserved_offset = 0;
- if(res.reserved_offset + req.reserve_size > block_blob.size())
- {
- error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
- error_resp.message = "Internal error: failed to create block template";
- LOG_ERROR("Failed to calculate offset for ");
- return false;
- }
blobdata hashing_blob = get_block_hashing_blob(b);
res.prev_hash = string_tools::pod_to_hex(b.prev_id);
res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
@@ -1493,7 +1730,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_submitblock);
+ RPC_TRACKER(submitblock);
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
@@ -1549,7 +1786,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_generateblocks);
+ RPC_TRACKER(generateblocks);
CHECK_CORE_READY();
@@ -1724,12 +1961,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_last_block_header);
+ RPC_TRACKER(get_last_block_header);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LAST_BLOCK_HEADER>(invoke_http_mode::JON_RPC, "getlastblockheader", req, res, r))
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);
@@ -1755,11 +1993,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_block_header_by_hash);
+ RPC_TRACKER(get_block_header_by_hash);
bool r;
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);
+
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
crypto::hash block_hash;
bool hash_parsed = parse_hash256(hash, block_hash);
@@ -1815,7 +2055,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request& req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_block_headers_range);
+ RPC_TRACKER(get_block_headers_range);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r))
return r;
@@ -1827,6 +2067,7 @@ namespace cryptonote
error_resp.message = "Invalid start/end heights.";
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);
@@ -1867,7 +2108,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_block_header_by_height);
+ RPC_TRACKER(get_block_header_by_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT>(invoke_http_mode::JON_RPC, "getblockheaderbyheight", req, res, r))
return r;
@@ -1878,6 +2119,7 @@ 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);
@@ -1901,11 +2143,13 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block(const COMMAND_RPC_GET_BLOCK::request& req, COMMAND_RPC_GET_BLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_block);
+ RPC_TRACKER(get_block);
bool r;
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())
{
@@ -1963,7 +2207,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_connections(const COMMAND_RPC_GET_CONNECTIONS::request& req, COMMAND_RPC_GET_CONNECTIONS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_connections);
+ RPC_TRACKER(get_connections);
res.connections = m_p2p.get_payload_object().get_connections();
@@ -1974,16 +2218,24 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- return on_get_info(req, res, ctx);
+ on_get_info(req, res, ctx);
+ if (res.status != CORE_RPC_STATUS_OK)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = res.status;
+ return false;
+ }
+ return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_hard_fork_info);
+ RPC_TRACKER(hard_fork_info);
bool r;
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();
@@ -1995,7 +2247,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_bans);
+ RPC_TRACKER(get_bans);
auto now = time(nullptr);
std::map<std::string, time_t> blocked_hosts = m_p2p.get_blocked_hosts();
@@ -2059,7 +2311,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_set_bans);
+ RPC_TRACKER(set_bans);
for (auto i = req.bans.begin(); i != req.bans.end(); ++i)
{
@@ -2107,7 +2359,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_flush_txpool(const COMMAND_RPC_FLUSH_TRANSACTION_POOL::request& req, COMMAND_RPC_FLUSH_TRANSACTION_POOL::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_flush_txpool);
+ RPC_TRACKER(flush_txpool);
bool failed = false;
std::vector<crypto::hash> txids;
@@ -2162,12 +2414,22 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_output_histogram);
+ RPC_TRACKER(get_output_histogram);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
+ size_t amounts = req.amounts.size();
+ if (restricted && amounts == 0)
+ {
+ res.status = "Restricted RPC will not serve histograms on the whole blockchain. Use your own node.";
+ 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";
@@ -2199,7 +2461,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_version);
+ RPC_TRACKER(get_version);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_VERSION>(invoke_http_mode::JON_RPC, "get_version", req, res, r))
return r;
@@ -2212,7 +2474,14 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_coinbase_tx_sum(const COMMAND_RPC_GET_COINBASE_TX_SUM::request& req, COMMAND_RPC_GET_COINBASE_TX_SUM::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_coinbase_tx_sum);
+ RPC_TRACKER(get_coinbase_tx_sum);
+ const uint64_t bc_height = m_core.get_current_blockchain_height();
+ if (req.height >= bc_height || req.count > bc_height)
+ {
+ res.status = "height or count is too large";
+ return true;
+ }
+ CHECK_PAYMENT_MIN1(req, res, COST_PER_COINBASE_TX_SUM_BLOCK * req.count, false);
std::pair<uint64_t, uint64_t> amounts = m_core.get_coinbase_tx_sum(req.height, req.count);
res.emission_amount = amounts.first;
res.fee_amount = amounts.second;
@@ -2222,11 +2491,12 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_base_fee_estimate(const COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_base_fee_estimate);
+ RPC_TRACKER(get_base_fee_estimate);
bool r;
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);
res.fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.grace_blocks);
res.quantization_mask = Blockchain::get_fee_quantization_mask();
res.status = CORE_RPC_STATUS_OK;
@@ -2235,7 +2505,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_alternate_chains(const COMMAND_RPC_GET_ALTERNATE_CHAINS::request& req, COMMAND_RPC_GET_ALTERNATE_CHAINS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_alternate_chains);
+ RPC_TRACKER(get_alternate_chains);
try
{
std::vector<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains();
@@ -2268,7 +2538,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_limit);
+ RPC_TRACKER(get_limit);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LIMIT>(invoke_http_mode::JON, "/get_limit", req, res, r))
return r;
@@ -2281,7 +2551,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_set_limit);
+ RPC_TRACKER(set_limit);
// -1 = reset to default
// 0 = do not modify
@@ -2321,7 +2591,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_out_peers);
+ RPC_TRACKER(out_peers);
if (req.set)
m_p2p.change_max_out_public_peers(req.out_peers);
res.out_peers = m_p2p.get_max_out_public_peers();
@@ -2331,7 +2601,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_in_peers);
+ RPC_TRACKER(in_peers);
if (req.set)
m_p2p.change_max_in_public_peers(req.in_peers);
res.in_peers = m_p2p.get_max_in_public_peers();
@@ -2341,7 +2611,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_update);
+ RPC_TRACKER(update);
if (m_core.offline())
{
@@ -2443,7 +2713,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request& req, COMMAND_RPC_POP_BLOCKS::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_pop_blocks);
+ RPC_TRACKER(pop_blocks);
m_core.get_blockchain_storage().pop_blocks(req.nblocks);
@@ -2455,7 +2725,8 @@ 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)
{
- PERF_TIMER(on_relay_tx);
+ RPC_TRACKER(relay_tx);
+ CHECK_PAYMENT_MIN1(req, res, req.txids.size() * COST_PER_TX_RELAY, false);
bool failed = false;
res.status = "";
@@ -2501,7 +2772,8 @@ 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)
{
- PERF_TIMER(on_sync_info);
+ 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);
@@ -2530,10 +2802,12 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_txpool_backlog);
+ RPC_TRACKER(get_txpool_backlog);
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))
{
@@ -2548,11 +2822,16 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_output_distribution);
+ RPC_TRACKER(get_output_distribution);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::JON_RPC, "get_output_distribution", req, res, r))
return r;
+ 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
@@ -2583,12 +2862,17 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_output_distribution_bin(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, const connection_context *ctx)
{
- PERF_TIMER(on_get_output_distribution_bin);
+ RPC_TRACKER(get_output_distribution_bin);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::BIN, "/get_output_distribution.bin", req, res, r))
return r;
+ 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)
@@ -2624,6 +2908,8 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_prune_blockchain(const COMMAND_RPC_PRUNE_BLOCKCHAIN::request& req, COMMAND_RPC_PRUNE_BLOCKCHAIN::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
+ RPC_TRACKER(prune_blockchain);
+
try
{
if (!(req.check ? m_core.check_blockchain_pruning() : m_core.prune_blockchain()))
@@ -2641,13 +2927,248 @@ namespace cryptonote
error_resp.message = "Failed to prune blockchain";
return false;
}
+ res.status = CORE_RPC_STATUS_OK;
+ 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_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;
+ size_t reserved_offset;
+ if (!get_block_template(m_rpc_payment->get_payment_address(), NULL, extra_nonce, reserved_offset, difficulty, height, expected_reward, 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_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_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_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_access_data", req, res, r))
+ return r;
+
+ if (!m_rpc_payment)
+ {
+ res.status = "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_access_account", req, res, r))
+ return r;
+
+ if (!m_rpc_payment)
+ {
+ res.status = "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"
@@ -2686,4 +3207,22 @@ namespace cryptonote
, "Specify username:password for the bootstrap daemon login"
, ""
};
+
+ 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
+ };
} // namespace cryptonote
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index fe03012b7..6655d621e 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -42,6 +42,7 @@
#include "cryptonote_core/cryptonote_core.h"
#include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#include "rpc_payment.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc"
@@ -71,6 +72,9 @@ namespace cryptonote
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
+ static const command_line::arg_descriptor<std::string> arg_rpc_payment_address;
+ static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_difficulty;
+ static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_credits;
typedef epee::net_utils::connection_context_base connection_context;
@@ -78,6 +82,7 @@ namespace cryptonote
core& cr
, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p
);
+ ~core_rpc_server();
static void init_options(boost::program_options::options_description& desc);
bool init(
@@ -111,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("/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_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_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)
@@ -169,6 +174,12 @@ namespace cryptonote
MAP_JON_RPC_WE("get_txpool_backlog", on_get_txpool_backlog, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG)
MAP_JON_RPC_WE("get_output_distribution", on_get_output_distribution, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION)
MAP_JON_RPC_WE_IF("prune_blockchain", on_prune_blockchain, COMMAND_RPC_PRUNE_BLOCKCHAIN, !m_restricted)
+ MAP_JON_RPC_WE("rpc_access_info", on_rpc_access_info, COMMAND_RPC_ACCESS_INFO)
+ MAP_JON_RPC_WE("rpc_access_submit_nonce",on_rpc_access_submit_nonce, COMMAND_RPC_ACCESS_SUBMIT_NONCE)
+ MAP_JON_RPC_WE("rpc_access_pay", on_rpc_access_pay, COMMAND_RPC_ACCESS_PAY)
+ MAP_JON_RPC_WE_IF("rpc_access_tracking", on_rpc_access_tracking, COMMAND_RPC_ACCESS_TRACKING, !m_restricted)
+ MAP_JON_RPC_WE_IF("rpc_access_data", on_rpc_access_data, COMMAND_RPC_ACCESS_DATA, !m_restricted)
+ MAP_JON_RPC_WE_IF("rpc_access_account", on_rpc_access_account, COMMAND_RPC_ACCESS_ACCOUNT, !m_restricted)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -236,6 +247,12 @@ namespace cryptonote
bool on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_prune_blockchain(const COMMAND_RPC_PRUNE_BLOCKCHAIN::request& req, COMMAND_RPC_PRUNE_BLOCKCHAIN::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
+ bool 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 = NULL);
+ bool 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 = NULL);
+ bool 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 = NULL);
+ bool 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 = NULL);
+ bool 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 = NULL);
+ bool 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 = NULL);
//-----------------------
private:
@@ -252,6 +269,8 @@ private:
enum invoke_http_mode { JON, BIN, JON_RPC };
template <typename COMMAND_TYPE>
bool use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r);
+ bool get_block_template(const account_public_address &address, const crypto::hash *prev_block, const cryptonote::blobdata &extra_nonce, size_t &reserved_offset, cryptonote::difficulty_type &difficulty, uint64_t &height, uint64_t &expected_reward, block &b, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, epee::json_rpc::error &error_resp);
+ bool check_payment(const std::string &client, uint64_t payment, const std::string &rpc, bool same_ts, std::string &message, uint64_t &credits, std::string &top_hash);
core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
@@ -260,10 +279,10 @@ private:
bool m_should_use_bootstrap_daemon;
std::chrono::system_clock::time_point m_bootstrap_height_check_time;
bool m_was_bootstrap_ever_used;
- network_type m_nettype;
bool m_restricted;
epee::critical_section m_host_fails_score_lock;
std::map<std::string, uint64_t> m_host_fails_score;
+ std::unique_ptr<rpc_payment> m_rpc_payment;
};
}
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 2760260f6..89c88a835 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -78,6 +78,7 @@ namespace cryptonote
#define CORE_RPC_STATUS_OK "OK"
#define CORE_RPC_STATUS_BUSY "BUSY"
#define CORE_RPC_STATUS_NOT_MINING "NOT MINING"
+#define CORE_RPC_STATUS_PAYMENT_REQUIRED "PAYMENT REQUIRED"
// When making *any* change here, bump minor
// If the change is incompatible, then bump major and set minor to 0
@@ -91,26 +92,67 @@ namespace cryptonote
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
+ struct rpc_request_base
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct rpc_response_base
+ {
+ std::string status;
+ bool untrusted;
+
+ rpc_response_base(): untrusted(false) {}
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct rpc_access_request_base: public rpc_request_base
+ {
+ std::string client;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ KV_SERIALIZE(client)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct rpc_access_response_base: public rpc_response_base
+ {
+ uint64_t credits;
+ std::string top_hash;
+
+ rpc_access_response_base(): credits(0) {}
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
+ KV_SERIALIZE(credits)
+ KV_SERIALIZE(top_hash)
+ END_KV_SERIALIZE_MAP()
+ };
+
struct COMMAND_RPC_GET_HEIGHT
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
uint64_t height;
- std::string status;
- bool untrusted;
std::string hash;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(height)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
KV_SERIALIZE(hash)
END_KV_SERIALIZE_MAP()
};
@@ -120,13 +162,14 @@ namespace cryptonote
struct COMMAND_RPC_GET_BLOCKS_FAST
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::list<crypto::hash> block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */
uint64_t start_height;
bool prune;
bool no_miner_tx;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids)
KV_SERIALIZE(start_height)
KV_SERIALIZE(prune)
@@ -153,22 +196,19 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<block_complete_entry> blocks;
uint64_t start_height;
uint64_t current_height;
- std::string status;
std::vector<block_output_indices> output_indices;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(blocks)
KV_SERIALIZE(start_height)
KV_SERIALIZE(current_height)
- KV_SERIALIZE(status)
KV_SERIALIZE(output_indices)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -176,25 +216,23 @@ namespace cryptonote
struct COMMAND_RPC_GET_BLOCKS_BY_HEIGHT
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<uint64_t> heights;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(heights)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<block_complete_entry> blocks;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(blocks)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -202,23 +240,21 @@ namespace cryptonote
struct COMMAND_RPC_GET_ALT_BLOCKS_HASHES
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<std::string> blks_hashes;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(blks_hashes)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -226,31 +262,29 @@ namespace cryptonote
struct COMMAND_RPC_GET_HASHES_FAST
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::list<crypto::hash> block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */
uint64_t start_height;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids)
KV_SERIALIZE(start_height)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<crypto::hash> m_block_ids;
uint64_t start_height;
uint64_t current_height;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
KV_SERIALIZE(start_height)
KV_SERIALIZE(current_height)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -288,7 +322,7 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_GET_TRANSACTIONS
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<std::string> txs_hashes;
bool decode_as_json;
@@ -296,6 +330,7 @@ namespace cryptonote
bool split;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(txs_hashes)
KV_SERIALIZE(decode_as_json)
KV_SERIALIZE_OPT(prune, false)
@@ -341,7 +376,7 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
// older compatibility stuff
std::vector<std::string> txs_as_hex; //transactions blobs as hex (old compat)
@@ -352,16 +387,13 @@ namespace cryptonote
// new style
std::vector<entry> txs;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(txs_as_hex)
KV_SERIALIZE(txs_as_json)
KV_SERIALIZE(txs)
KV_SERIALIZE(missed_tx)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -376,27 +408,25 @@ namespace cryptonote
SPENT_IN_POOL = 2,
};
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<std::string> key_images;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(key_images)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<int> spent_status;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(spent_status)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -405,25 +435,24 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
crypto::hash txid;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE_VAL_POD_AS_BLOB(txid)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<uint64_t> o_indexes;
- std::string status;
- bool untrusted;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(o_indexes)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -442,12 +471,13 @@ namespace cryptonote
struct COMMAND_RPC_GET_OUTPUTS_BIN
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<get_outputs_out> outputs;
bool get_txid;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(outputs)
KV_SERIALIZE_OPT(get_txid, true)
END_KV_SERIALIZE_MAP()
@@ -471,16 +501,13 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<outkey> outs;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(outs)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -488,12 +515,13 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_GET_OUTPUTS
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<get_outputs_out> outputs;
bool get_txid;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(outputs)
KV_SERIALIZE(get_txid)
END_KV_SERIALIZE_MAP()
@@ -517,16 +545,13 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
std::vector<outkey> outs;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(outs)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -534,13 +559,14 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_SEND_RAW_TX
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::string tx_as_hex;
bool do_not_relay;
bool do_sanity_checks;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base);
KV_SERIALIZE(tx_as_hex)
KV_SERIALIZE_OPT(do_not_relay, false)
KV_SERIALIZE_OPT(do_sanity_checks, true)
@@ -549,9 +575,8 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::string reason;
bool not_relayed;
bool low_mixin;
@@ -564,10 +589,9 @@ namespace cryptonote
bool not_rct;
bool too_few_outputs;
bool sanity_check_failed;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(reason)
KV_SERIALIZE(not_relayed)
KV_SERIALIZE(low_mixin)
@@ -580,7 +604,6 @@ namespace cryptonote
KV_SERIALIZE(not_rct)
KV_SERIALIZE(too_few_outputs)
KV_SERIALIZE(sanity_check_failed)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -588,7 +611,7 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_START_MINING
{
- struct request_t
+ struct request_t: public rpc_request_base
{
std::string miner_address;
uint64_t threads_count;
@@ -596,6 +619,7 @@ namespace cryptonote
bool ignore_battery;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(miner_address)
KV_SERIALIZE(threads_count)
KV_SERIALIZE(do_background_mining)
@@ -604,12 +628,10 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -617,17 +639,16 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_GET_INFO
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
-
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base);
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
uint64_t height;
uint64_t target_height;
uint64_t difficulty;
@@ -657,7 +678,6 @@ namespace cryptonote
uint64_t start_time;
uint64_t free_space;
bool offline;
- bool untrusted;
std::string bootstrap_daemon_address;
uint64_t height_without_bootstrap;
bool was_bootstrap_ever_used;
@@ -666,7 +686,7 @@ namespace cryptonote
std::string version;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(height)
KV_SERIALIZE(target_height)
KV_SERIALIZE(difficulty)
@@ -696,7 +716,6 @@ namespace cryptonote
KV_SERIALIZE(start_time)
KV_SERIALIZE(free_space)
KV_SERIALIZE(offline)
- KV_SERIALIZE(untrusted)
KV_SERIALIZE(bootstrap_daemon_address)
KV_SERIALIZE(height_without_bootstrap)
KV_SERIALIZE(was_bootstrap_ever_used)
@@ -712,18 +731,17 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_GET_NET_STATS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
-
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
uint64_t start_time;
uint64_t total_packets_in;
uint64_t total_bytes_in;
@@ -731,7 +749,7 @@ namespace cryptonote
uint64_t total_bytes_out;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(start_time)
KV_SERIALIZE(total_packets_in)
KV_SERIALIZE(total_bytes_in)
@@ -745,21 +763,19 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_STOP_MINING
{
- struct request_t
+ struct request_t: public rpc_request_base
{
-
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -768,18 +784,17 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_MINING_STATUS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
-
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
bool active;
uint64_t speed;
uint32_t threads_count;
@@ -797,7 +812,7 @@ namespace cryptonote
uint64_t difficulty_top64;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(active)
KV_SERIALIZE(speed)
KV_SERIALIZE(threads_count)
@@ -821,21 +836,19 @@ namespace cryptonote
//-----------------------------------------------
struct COMMAND_RPC_SAVE_BC
{
- struct request_t
+ struct request_t: public rpc_request_base
{
-
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -846,14 +859,13 @@ namespace cryptonote
{
typedef std::list<std::string> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
uint64_t count;
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(count)
- KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -869,7 +881,7 @@ namespace cryptonote
struct COMMAND_RPC_GETBLOCKTEMPLATE
{
- struct request_t
+ struct request_t: public rpc_request_base
{
uint64_t reserve_size; //max 255 bytes
std::string wallet_address;
@@ -877,6 +889,7 @@ namespace cryptonote
std::string extra_nonce;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(reserve_size)
KV_SERIALIZE(wallet_address)
KV_SERIALIZE(prev_block)
@@ -885,7 +898,7 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
uint64_t difficulty;
std::string wide_difficulty;
@@ -894,14 +907,14 @@ namespace cryptonote
uint64_t reserved_offset;
uint64_t expected_reward;
std::string prev_hash;
+ uint64_t seed_height;
std::string seed_hash;
std::string next_seed_hash;
blobdata blocktemplate_blob;
blobdata blockhashing_blob;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(difficulty)
KV_SERIALIZE(wide_difficulty)
KV_SERIALIZE(difficulty_top64)
@@ -909,10 +922,9 @@ namespace cryptonote
KV_SERIALIZE(reserved_offset)
KV_SERIALIZE(expected_reward)
KV_SERIALIZE(prev_hash)
+ KV_SERIALIZE(seed_height)
KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(blockhashing_blob)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
KV_SERIALIZE(seed_hash)
KV_SERIALIZE(next_seed_hash)
END_KV_SERIALIZE_MAP()
@@ -924,12 +936,10 @@ namespace cryptonote
{
typedef std::vector<std::string> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -937,7 +947,7 @@ namespace cryptonote
struct COMMAND_RPC_GENERATEBLOCKS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
uint64_t amount_of_blocks;
std::string wallet_address;
@@ -945,6 +955,7 @@ namespace cryptonote
uint32_t starting_nonce;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(amount_of_blocks)
KV_SERIALIZE(wallet_address)
KV_SERIALIZE(prev_block)
@@ -953,16 +964,15 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
uint64_t height;
std::vector<std::string> blocks;
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(height)
KV_SERIALIZE(blocks)
- KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1021,26 +1031,24 @@ namespace cryptonote
struct COMMAND_RPC_GET_LAST_BLOCK_HEADER
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
bool fill_pow_hash;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE_OPT(fill_pow_hash, false);
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
block_header_response block_header;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(block_header)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1049,13 +1057,14 @@ namespace cryptonote
struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::string hash;
std::vector<std::string> hashes;
bool fill_pow_hash;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(hash)
KV_SERIALIZE(hashes)
KV_SERIALIZE_OPT(fill_pow_hash, false);
@@ -1063,18 +1072,15 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
block_header_response block_header;
std::vector<block_header_response> block_headers;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(block_header)
KV_SERIALIZE(block_headers)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1082,28 +1088,26 @@ namespace cryptonote
struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
uint64_t height;
bool fill_pow_hash;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(height)
KV_SERIALIZE_OPT(fill_pow_hash, false);
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
block_header_response block_header;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(block_header)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1111,13 +1115,14 @@ namespace cryptonote
struct COMMAND_RPC_GET_BLOCK
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::string hash;
uint64_t height;
bool fill_pow_hash;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(hash)
KV_SERIALIZE(height)
KV_SERIALIZE_OPT(fill_pow_hash, false);
@@ -1125,24 +1130,21 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
block_header_response block_header;
std::string miner_tx_hash;
std::vector<std::string> tx_hashes;
std::string blob;
std::string json;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(block_header)
KV_SERIALIZE(miner_tx_hash)
KV_SERIALIZE(tx_hashes)
- KV_SERIALIZE(status)
KV_SERIALIZE(blob)
KV_SERIALIZE(json)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1154,19 +1156,20 @@ namespace cryptonote
uint32_t ip;
uint16_t port;
uint16_t rpc_port;
+ uint32_t rpc_credits_per_hash;
uint64_t last_seen;
uint32_t pruning_seed;
peer() = default;
- peer(uint64_t id, const std::string &host, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port)
- : id(id), host(host), ip(0), port(0), rpc_port(rpc_port), last_seen(last_seen), pruning_seed(pruning_seed)
+ peer(uint64_t id, const std::string &host, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port, uint32_t rpc_credits_per_hash)
+ : id(id), host(host), ip(0), port(0), rpc_port(rpc_port), rpc_credits_per_hash(rpc_credits_per_hash), last_seen(last_seen), pruning_seed(pruning_seed)
{}
- peer(uint64_t id, const std::string &host, uint16_t port, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port)
- : id(id), host(host), ip(0), port(port), rpc_port(rpc_port), last_seen(last_seen), pruning_seed(pruning_seed)
+ peer(uint64_t id, const std::string &host, uint16_t port, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port, uint32_t rpc_credits_per_hash)
+ : id(id), host(host), ip(0), port(port), rpc_port(rpc_port), rpc_credits_per_hash(rpc_credits_per_hash), last_seen(last_seen), pruning_seed(pruning_seed)
{}
- peer(uint64_t id, uint32_t ip, uint16_t port, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port)
- : id(id), host(epee::string_tools::get_ip_string_from_int32(ip)), ip(ip), port(port), rpc_port(rpc_port), last_seen(last_seen), pruning_seed(pruning_seed)
+ peer(uint64_t id, uint32_t ip, uint16_t port, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port, uint32_t rpc_credits_per_hash)
+ : id(id), host(epee::string_tools::get_ip_string_from_int32(ip)), ip(ip), port(port), rpc_port(rpc_port), rpc_credits_per_hash(rpc_credits_per_hash), last_seen(last_seen), pruning_seed(pruning_seed)
{}
BEGIN_KV_SERIALIZE_MAP()
@@ -1175,6 +1178,7 @@ namespace cryptonote
KV_SERIALIZE(ip)
KV_SERIALIZE(port)
KV_SERIALIZE_OPT(rpc_port, (uint16_t)0)
+ KV_SERIALIZE_OPT(rpc_credits_per_hash, (uint32_t)0)
KV_SERIALIZE(last_seen)
KV_SERIALIZE_OPT(pruning_seed, (uint32_t)0)
END_KV_SERIALIZE_MAP()
@@ -1182,24 +1186,24 @@ namespace cryptonote
struct COMMAND_RPC_GET_PEER_LIST
{
- struct request_t
+ struct request_t: public rpc_request_base
{
bool public_only;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(public_only, true)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
std::vector<peer> white_list;
std::vector<peer> gray_list;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(white_list)
KV_SERIALIZE(gray_list)
END_KV_SERIALIZE_MAP()
@@ -1212,42 +1216,44 @@ namespace cryptonote
std::string host;
uint64_t last_seen;
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)
- : 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()
KV_SERIALIZE(host)
KV_SERIALIZE(last_seen)
KV_SERIALIZE(rpc_port)
+ KV_SERIALIZE(rpc_credits_per_hash)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_GET_PUBLIC_NODES
{
- struct request_t
+ struct request_t: public rpc_request_base
{
bool gray;
bool white;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(gray, false)
KV_SERIALIZE_OPT(white, true)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
std::vector<public_node> gray;
std::vector<public_node> white;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(gray)
KV_SERIALIZE(white)
END_KV_SERIALIZE_MAP()
@@ -1257,21 +1263,21 @@ namespace cryptonote
struct COMMAND_RPC_SET_LOG_HASH_RATE
{
- struct request_t
+ struct request_t: public rpc_request_base
{
bool visible;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(visible)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1279,21 +1285,21 @@ namespace cryptonote
struct COMMAND_RPC_SET_LOG_LEVEL
{
- struct request_t
+ struct request_t: public rpc_request_base
{
int8_t level;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(level)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1301,23 +1307,23 @@ namespace cryptonote
struct COMMAND_RPC_SET_LOG_CATEGORIES
{
- struct request_t
+ struct request_t: public rpc_request_base
{
std::string categories;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(categories)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
std::string categories;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(categories)
END_KV_SERIALIZE_MAP()
};
@@ -1376,25 +1382,23 @@ namespace cryptonote
struct COMMAND_RPC_GET_TRANSACTION_POOL
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<tx_info> transactions;
std::vector<spent_key_image_info> spent_key_images;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(transactions)
KV_SERIALIZE(spent_key_images)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1402,23 +1406,21 @@ namespace cryptonote
struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<crypto::hash> tx_hashes;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(tx_hashes)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1426,23 +1428,21 @@ namespace cryptonote
struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<std::string> tx_hashes;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(tx_hashes)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1457,23 +1457,21 @@ namespace cryptonote
struct COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<tx_backlog_entry> backlog;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(backlog)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1527,23 +1525,21 @@ namespace cryptonote
struct COMMAND_RPC_GET_TRANSACTION_POOL_STATS
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
txpool_stats pool_stats;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(pool_stats)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1551,20 +1547,20 @@ namespace cryptonote
struct COMMAND_RPC_GET_CONNECTIONS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
std::list<connection_info> connections;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(connections)
END_KV_SERIALIZE_MAP()
};
@@ -1573,13 +1569,14 @@ namespace cryptonote
struct COMMAND_RPC_GET_BLOCK_HEADERS_RANGE
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
uint64_t start_height;
uint64_t end_height;
bool fill_pow_hash;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(start_height)
KV_SERIALIZE(end_height)
KV_SERIALIZE_OPT(fill_pow_hash, false);
@@ -1587,16 +1584,13 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<block_header_response> headers;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(headers)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1631,19 +1625,18 @@ namespace cryptonote
struct COMMAND_RPC_STOP_DAEMON
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1651,19 +1644,18 @@ namespace cryptonote
struct COMMAND_RPC_FAST_EXIT
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1671,25 +1663,23 @@ namespace cryptonote
struct COMMAND_RPC_GET_LIMIT
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
uint64_t limit_up;
uint64_t limit_down;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(limit_up)
KV_SERIALIZE(limit_down)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1697,26 +1687,26 @@ namespace cryptonote
struct COMMAND_RPC_SET_LIMIT
{
- struct request_t
+ struct request_t: public rpc_request_base
{
int64_t limit_down; // all limits (for get and set) are kB/s
int64_t limit_up;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(limit_down)
KV_SERIALIZE(limit_up)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
int64_t limit_up;
int64_t limit_down;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(limit_up)
KV_SERIALIZE(limit_down)
END_KV_SERIALIZE_MAP()
@@ -1726,25 +1716,26 @@ namespace cryptonote
struct COMMAND_RPC_OUT_PEERS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
bool set;
uint32_t out_peers;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(set, true)
KV_SERIALIZE(out_peers)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
uint32_t out_peers;
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(out_peers)
- KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1752,25 +1743,25 @@ namespace cryptonote
struct COMMAND_RPC_IN_PEERS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
bool set;
uint32_t in_peers;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(set, true)
KV_SERIALIZE(in_peers)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
uint32_t in_peers;
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(in_peers)
- KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1778,17 +1769,18 @@ namespace cryptonote
struct COMMAND_RPC_HARD_FORK_INFO
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
uint8_t version;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(version)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
uint8_t version;
bool enabled;
@@ -1798,10 +1790,9 @@ namespace cryptonote
uint8_t voting;
uint32_t state;
uint64_t earliest_height;
- std::string status;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(version)
KV_SERIALIZE(enabled)
KV_SERIALIZE(window)
@@ -1810,8 +1801,6 @@ namespace cryptonote
KV_SERIALIZE(voting)
KV_SERIALIZE(state)
KV_SERIALIZE(earliest_height)
- KV_SERIALIZE(status)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1832,20 +1821,20 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
std::vector<ban> bans;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(bans)
END_KV_SERIALIZE_MAP()
};
@@ -1869,22 +1858,21 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct request_t
+ struct request_t: public rpc_request_base
{
std::vector<ban> bans;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(bans)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1919,22 +1907,21 @@ namespace cryptonote
struct COMMAND_RPC_FLUSH_TRANSACTION_POOL
{
- struct request_t
+ struct request_t: public rpc_request_base
{
std::vector<std::string> txids;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE(txids)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1942,7 +1929,7 @@ namespace cryptonote
struct COMMAND_RPC_GET_OUTPUT_HISTOGRAM
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<uint64_t> amounts;
uint64_t min_count;
@@ -1951,6 +1938,7 @@ namespace cryptonote
uint64_t recent_cutoff;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base);
KV_SERIALIZE(amounts);
KV_SERIALIZE(min_count);
KV_SERIALIZE(max_count);
@@ -1979,16 +1967,13 @@ namespace cryptonote
entry() {}
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<entry> histogram;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(histogram)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1996,25 +1981,23 @@ namespace cryptonote
struct COMMAND_RPC_GET_VERSION
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
uint32_t version;
bool release;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(version)
KV_SERIALIZE(release)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2022,26 +2005,26 @@ namespace cryptonote
struct COMMAND_RPC_GET_COINBASE_TX_SUM
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
uint64_t height;
uint64_t count;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base);
KV_SERIALIZE(height);
KV_SERIALIZE(count);
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
uint64_t emission_amount;
uint64_t fee_amount;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(emission_amount)
KV_SERIALIZE(fee_amount)
END_KV_SERIALIZE_MAP()
@@ -2051,28 +2034,26 @@ namespace cryptonote
struct COMMAND_RPC_GET_BASE_FEE_ESTIMATE
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
uint64_t grace_blocks;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(grace_blocks)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
uint64_t fee;
uint64_t quantization_mask;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(fee)
KV_SERIALIZE_OPT(quantization_mask, (uint64_t)1)
- KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2080,9 +2061,10 @@ namespace cryptonote
struct COMMAND_RPC_GET_ALTERNATE_CHAINS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2110,13 +2092,12 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
std::vector<chain_info> chains;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(chains)
END_KV_SERIALIZE_MAP()
};
@@ -2125,21 +2106,21 @@ namespace cryptonote
struct COMMAND_RPC_UPDATE
{
- struct request_t
+ struct request_t: public rpc_request_base
{
std::string command;
std::string path;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(command);
- KV_SERIALIZE(path);
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ KV_SERIALIZE(command)
+ KV_SERIALIZE(path)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
bool update;
std::string version;
std::string user_uri;
@@ -2148,7 +2129,7 @@ namespace cryptonote
std::string path;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(update)
KV_SERIALIZE(version)
KV_SERIALIZE(user_uri)
@@ -2162,22 +2143,21 @@ namespace cryptonote
struct COMMAND_RPC_RELAY_TX
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<std::string> txids;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(txids)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
-
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2185,9 +2165,10 @@ namespace cryptonote
struct COMMAND_RPC_SYNC_INFO
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2222,9 +2203,8 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
uint64_t height;
uint64_t target_height;
uint32_t next_needed_pruning_seed;
@@ -2233,7 +2213,7 @@ namespace cryptonote
std::string overview;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(height)
KV_SERIALIZE(target_height)
KV_SERIALIZE(next_needed_pruning_seed)
@@ -2247,7 +2227,7 @@ namespace cryptonote
struct COMMAND_RPC_GET_OUTPUT_DISTRIBUTION
{
- struct request_t
+ struct request_t: public rpc_access_request_base
{
std::vector<uint64_t> amounts;
uint64_t from_height;
@@ -2257,6 +2237,7 @@ namespace cryptonote
bool compress;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(amounts)
KV_SERIALIZE_OPT(from_height, (uint64_t)0)
KV_SERIALIZE_OPT(to_height, (uint64_t)0)
@@ -2309,16 +2290,213 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
- struct response_t
+ struct response_t: public rpc_access_response_base
{
- std::string status;
std::vector<distribution> distributions;
- bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
KV_SERIALIZE(distributions)
- KV_SERIALIZE(untrusted)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ struct COMMAND_RPC_ACCESS_INFO
+ {
+ struct request_t: public rpc_access_request_base
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t: public rpc_access_response_base
+ {
+ std::string hashing_blob;
+ uint64_t seed_height;
+ std::string seed_hash;
+ std::string next_seed_hash;
+ uint32_t cookie;
+ uint64_t diff;
+ uint64_t credits_per_hash_found;
+ uint64_t height;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
+ KV_SERIALIZE(hashing_blob)
+ KV_SERIALIZE(seed_height)
+ KV_SERIALIZE(seed_hash)
+ KV_SERIALIZE(next_seed_hash)
+ KV_SERIALIZE(cookie)
+ KV_SERIALIZE(diff)
+ KV_SERIALIZE(credits_per_hash_found)
+ KV_SERIALIZE(height)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ struct COMMAND_RPC_ACCESS_SUBMIT_NONCE
+ {
+ struct request_t: public rpc_access_request_base
+ {
+ uint32_t nonce;
+ uint32_t cookie;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
+ KV_SERIALIZE(nonce)
+ KV_SERIALIZE(cookie)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t: public rpc_access_response_base
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ struct COMMAND_RPC_ACCESS_PAY
+ {
+ struct request_t: public rpc_access_request_base
+ {
+ std::string paying_for;
+ uint64_t payment;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
+ KV_SERIALIZE(paying_for)
+ KV_SERIALIZE(payment)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t: public rpc_access_response_base
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_access_response_base)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ struct COMMAND_RPC_ACCESS_TRACKING
+ {
+ struct request_t: public rpc_request_base
+ {
+ bool clear;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ KV_SERIALIZE(clear)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct entry
+ {
+ std::string rpc;
+ uint64_t count;
+ uint64_t time;
+ uint64_t credits;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(rpc)
+ KV_SERIALIZE(count)
+ KV_SERIALIZE(time)
+ KV_SERIALIZE(credits)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response_t: public rpc_response_base
+ {
+ std::vector<entry> data;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
+ KV_SERIALIZE(data)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ struct COMMAND_RPC_ACCESS_DATA
+ {
+ struct request_t: public rpc_request_base
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct entry
+ {
+ std::string client;
+ uint64_t balance;
+ uint64_t last_update_time;
+ uint64_t credits_total;
+ uint64_t credits_used;
+ uint64_t nonces_good;
+ uint64_t nonces_stale;
+ uint64_t nonces_bad;
+ uint64_t nonces_dupe;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(client)
+ KV_SERIALIZE(balance)
+ KV_SERIALIZE(last_update_time)
+ KV_SERIALIZE(credits_total)
+ KV_SERIALIZE(credits_used)
+ KV_SERIALIZE(nonces_good)
+ KV_SERIALIZE(nonces_stale)
+ KV_SERIALIZE(nonces_bad)
+ KV_SERIALIZE(nonces_dupe)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response_t: public rpc_response_base
+ {
+ std::list<entry> entries;
+ uint32_t hashrate;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
+ KV_SERIALIZE(entries)
+ KV_SERIALIZE(hashrate)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ struct COMMAND_RPC_ACCESS_ACCOUNT
+ {
+ struct request_t: public rpc_request_base
+ {
+ std::string client;
+ int64_t delta_balance;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ KV_SERIALIZE(client)
+ KV_SERIALIZE_OPT(delta_balance, (int64_t)0)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t: public rpc_response_base
+ {
+ uint64_t credits;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
+ KV_SERIALIZE(credits)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2326,23 +2504,23 @@ namespace cryptonote
struct COMMAND_RPC_POP_BLOCKS
{
- struct request_t
+ struct request_t: public rpc_request_base
{
uint64_t nblocks;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(nblocks);
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ KV_SERIALIZE(nblocks)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
- std::string status;
uint64_t height;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(height)
END_KV_SERIALIZE_MAP()
};
@@ -2351,24 +2529,24 @@ namespace cryptonote
struct COMMAND_RPC_PRUNE_BLOCKCHAIN
{
- struct request_t
+ struct request_t: public rpc_request_base
{
bool check;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(check, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
- struct response_t
+ struct response_t: public rpc_response_base
{
bool pruned;
uint32_t pruning_seed;
- std::string status;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
+ KV_SERIALIZE_PARENT(rpc_response_base)
KV_SERIALIZE(pruned)
KV_SERIALIZE(pruning_seed)
END_KV_SERIALIZE_MAP()
diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h
index b13049e61..2fd42f43f 100644
--- a/src/rpc/core_rpc_server_error_codes.h
+++ b/src/rpc/core_rpc_server_error_codes.h
@@ -43,5 +43,34 @@
#define CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC -11
#define CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS -12
#define CORE_RPC_ERROR_CODE_REGTEST_REQUIRED -13
+#define CORE_RPC_ERROR_CODE_PAYMENT_REQUIRED -14
+#define CORE_RPC_ERROR_CODE_INVALID_CLIENT -15
+#define CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW -16
+#define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17
+#define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18
+static inline const char *get_rpc_server_error_message(int64_t code)
+{
+ switch (code)
+ {
+ case CORE_RPC_ERROR_CODE_WRONG_PARAM: return "Invalid parameter";
+ case CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT: return "Height is too large";
+ case CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE: return "Reserve size is too large";
+ case CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS: return "Wrong wallet address";
+ case CORE_RPC_ERROR_CODE_INTERNAL_ERROR: return "Internal error";
+ case CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB: return "Wrong block blob";
+ case CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED: return "Block not accepted";
+ case CORE_RPC_ERROR_CODE_CORE_BUSY: return "Core is busy";
+ case CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE: return "Wrong block blob size";
+ case CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC: return "Unsupported RPC";
+ case CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS: return "Mining to subaddress is not supported";
+ case CORE_RPC_ERROR_CODE_REGTEST_REQUIRED: return "Regtest mode required";
+ case CORE_RPC_ERROR_CODE_PAYMENT_REQUIRED: return "Payment required";
+ case CORE_RPC_ERROR_CODE_INVALID_CLIENT: return "Invalid client";
+ case CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW: return "Payment too low";
+ case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment";
+ case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment";
+ default: MERROR("Unknown error: " << code); return "Unknown error";
+ }
+}
diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h
index 2a43811cf..e64f5f163 100644
--- a/src/rpc/message_data_structs.h
+++ b/src/rpc/message_data_structs.h
@@ -80,6 +80,7 @@ namespace rpc
uint32_t ip;
uint16_t port;
uint16_t rpc_port;
+ uint32_t rpc_credits_per_hash;
uint64_t last_seen;
uint32_t pruning_seed;
};
diff --git a/src/rpc/rpc_payment.cpp b/src/rpc/rpc_payment.cpp
new file mode 100644
index 000000000..0637db728
--- /dev/null
+++ b/src/rpc/rpc_payment.cpp
@@ -0,0 +1,402 @@
+// Copyright (c) 2018-2019, 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.
+
+#include <boost/archive/portable_binary_iarchive.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include "cryptonote_config.h"
+#include "include_base_utils.h"
+#include "string_tools.h"
+#include "file_io_utils.h"
+#include "int-util.h"
+#include "common/util.h"
+#include "serialization/crypto.h"
+#include "common/unordered_containers_boost_serialization.h"
+#include "cryptonote_basic/cryptonote_boost_serialization.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "cryptonote_basic/difficulty.h"
+#include "core_rpc_server_error_codes.h"
+#include "rpc_payment.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.payment"
+
+#define STALE_THRESHOLD 15 /* seconds */
+
+#define PENALTY_FOR_STALE 0
+#define PENALTY_FOR_BAD_HASH 20
+#define PENALTY_FOR_DUPLICATE 20
+
+#define DEFAULT_FLUSH_AGE (3600 * 24 * 180) // half a year
+#define DEFAULT_ZERO_FLUSH_AGE (60 * 2) // 2 minutes
+
+#define RPC_PAYMENT_NONCE_TAIL 0x58
+
+namespace cryptonote
+{
+ rpc_payment::client_info::client_info():
+ cookie(0),
+ top(crypto::null_hash),
+ previous_top(crypto::null_hash),
+ credits(0),
+ update_time(time(NULL)),
+ last_request_timestamp(0),
+ block_template_update_time(0),
+ credits_total(0),
+ credits_used(0),
+ nonces_good(0),
+ nonces_stale(0),
+ nonces_bad(0),
+ nonces_dupe(0)
+ {
+ }
+
+ rpc_payment::rpc_payment(const cryptonote::account_public_address &address, uint64_t diff, uint64_t credits_per_hash_found):
+ m_address(address),
+ m_diff(diff),
+ m_credits_per_hash_found(credits_per_hash_found),
+ m_credits_total(0),
+ m_credits_used(0),
+ m_nonces_good(0),
+ m_nonces_stale(0),
+ m_nonces_bad(0),
+ m_nonces_dupe(0)
+ {
+ }
+
+ uint64_t rpc_payment::balance(const crypto::public_key &client, int64_t delta)
+ {
+ client_info &info = m_client_info[client]; // creates if not found
+ uint64_t credits = info.credits;
+ if (delta > 0 && credits > std::numeric_limits<uint64_t>::max() - delta)
+ credits = std::numeric_limits<uint64_t>::max();
+ else if (delta < 0 && credits < (uint64_t)-delta)
+ credits = 0;
+ else
+ credits += delta;
+ if (delta)
+ MINFO("Client " << client << ": balance change from " << info.credits << " to " << credits);
+ return info.credits = credits;
+ }
+
+ bool rpc_payment::pay(const crypto::public_key &client, uint64_t ts, uint64_t payment, const std::string &rpc, bool same_ts, uint64_t &credits)
+ {
+ client_info &info = m_client_info[client]; // creates if not found
+ if (ts < info.last_request_timestamp || (ts == info.last_request_timestamp && !same_ts))
+ {
+ MDEBUG("Invalid ts: " << ts << " <= " << info.last_request_timestamp);
+ return false;
+ }
+ info.last_request_timestamp = ts;
+ if (info.credits < payment)
+ {
+ MDEBUG("Not enough credits: " << info.credits << " < " << payment);
+ credits = info.credits;
+ return false;
+ }
+ info.credits -= payment;
+ add64clamp(&info.credits_used, payment);
+ add64clamp(&m_credits_used, payment);
+ MDEBUG("client " << client << " paying " << payment << " for " << rpc << ", " << info.credits << " left");
+ credits = info.credits;
+ return true;
+ }
+
+ bool rpc_payment::get_info(const crypto::public_key &client, const std::function<bool(const cryptonote::blobdata&, cryptonote::block&, uint64_t &seed_height, crypto::hash &seed_hash)> &get_block_template, cryptonote::blobdata &hashing_blob, uint64_t &seed_height, crypto::hash &seed_hash, const crypto::hash &top, uint64_t &diff, uint64_t &credits_per_hash_found, uint64_t &credits, uint32_t &cookie)
+ {
+ client_info &info = m_client_info[client]; // creates if not found
+ const uint64_t now = time(NULL);
+ bool need_template = top != info.top || now >= info.block_template_update_time + STALE_THRESHOLD;
+ if (need_template)
+ {
+ cryptonote::block new_block;
+ uint64_t new_seed_height;
+ crypto::hash new_seed_hash;
+ cryptonote::blobdata extra_nonce("\x42\x42\x42\x42", 4);
+ if (!get_block_template(extra_nonce, new_block, new_seed_height, new_seed_hash))
+ return false;
+ if(!remove_field_from_tx_extra(new_block.miner_tx.extra, typeid(cryptonote::tx_extra_nonce)))
+ return false;
+ char data[33];
+ memcpy(data, &client, 32);
+ data[32] = RPC_PAYMENT_NONCE_TAIL;
+ crypto::hash hash;
+ cn_fast_hash(data, sizeof(data), hash);
+ extra_nonce = cryptonote::blobdata((const char*)&hash, 4);
+ if(!add_extra_nonce_to_tx_extra(new_block.miner_tx.extra, extra_nonce))
+ return false;
+ info.previous_block = std::move(info.block);
+ info.block = std::move(new_block);
+ hashing_blob = get_block_hashing_blob(info.block);
+ info.previous_hashing_blob = info.hashing_blob;
+ info.hashing_blob = hashing_blob;
+ info.previous_top = info.top;
+ info.previous_seed_height = info.seed_height;
+ info.seed_height = new_seed_height;
+ info.previous_seed_hash = info.seed_hash;
+ info.seed_hash = new_seed_hash;
+ std::swap(info.previous_payments, info.payments);
+ info.payments.clear();
+ ++info.cookie;
+ info.block_template_update_time = now;
+ }
+ info.top = top;
+ info.update_time = now;
+ hashing_blob = info.hashing_blob;
+ diff = m_diff;
+ credits_per_hash_found = m_credits_per_hash_found;
+ credits = info.credits;
+ seed_height = info.seed_height;
+ seed_hash = info.seed_hash;
+ cookie = info.cookie;
+ return true;
+ }
+
+ bool rpc_payment::submit_nonce(const crypto::public_key &client, uint32_t nonce, const crypto::hash &top, int64_t &error_code, std::string &error_message, uint64_t &credits, crypto::hash &hash, cryptonote::block &block, uint32_t cookie, bool &stale)
+ {
+ client_info &info = m_client_info[client]; // creates if not found
+ if (cookie != info.cookie && cookie != info.cookie - 1)
+ {
+ MWARNING("Very stale nonce");
+ ++m_nonces_stale;
+ ++info.nonces_stale;
+ sub64clamp(&info.credits, PENALTY_FOR_STALE * m_credits_per_hash_found);
+ error_code = CORE_RPC_ERROR_CODE_STALE_PAYMENT;
+ error_message = "Very stale payment";
+ return false;
+ }
+ const bool is_current = cookie == info.cookie;
+ MINFO("client " << client << " sends nonce: " << nonce << ", " << (is_current ? "current" : "stale"));
+ std::unordered_set<uint64_t> &payments = is_current ? info.payments : info.previous_payments;
+ if (!payments.insert(nonce).second)
+ {
+ MWARNING("Duplicate nonce " << nonce << " from " << (is_current ? "current" : "previous"));
+ ++m_nonces_dupe;
+ ++info.nonces_dupe;
+ sub64clamp(&info.credits, PENALTY_FOR_DUPLICATE * m_credits_per_hash_found);
+ error_code = CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT;
+ error_message = "Duplicate payment";
+ return false;
+ }
+
+ const uint64_t now = time(NULL);
+ if (!is_current)
+ {
+ if (now > info.update_time + STALE_THRESHOLD)
+ {
+ MWARNING("Nonce is stale (top " << top << ", should be " << info.top << " or within " << STALE_THRESHOLD << " seconds");
+ ++m_nonces_stale;
+ ++info.nonces_stale;
+ sub64clamp(&info.credits, PENALTY_FOR_STALE * m_credits_per_hash_found);
+ error_code = CORE_RPC_ERROR_CODE_STALE_PAYMENT;
+ error_message = "stale payment";
+ return false;
+ }
+ }
+
+ cryptonote::blobdata hashing_blob = is_current ? info.hashing_blob : info.previous_hashing_blob;
+ if (hashing_blob.size() < 43)
+ {
+ // not initialized ?
+ error_code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
+ error_message = "not initialized";
+ return false;
+ }
+
+ block = is_current ? info.block : info.previous_block;
+ *(uint32_t*)(hashing_blob.data() + 39) = SWAP32LE(nonce);
+ if (block.major_version >= RX_BLOCK_VERSION)
+ {
+ const uint64_t seed_height = is_current ? info.seed_height : info.previous_seed_height;
+ const crypto::hash &seed_hash = is_current ? info.seed_hash : info.previous_seed_hash;
+ const uint64_t height = cryptonote::get_block_height(block);
+ crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash.data, 0, 0);
+ }
+ else
+ {
+ const int cn_variant = hashing_blob[0] >= 7 ? hashing_blob[0] - 6 : 0;
+ crypto::cn_slow_hash(hashing_blob.data(), hashing_blob.size(), hash, cn_variant, cryptonote::get_block_height(block));
+ }
+ if (!check_hash(hash, m_diff))
+ {
+ MWARNING("Payment too low");
+ ++m_nonces_bad;
+ ++info.nonces_bad;
+ error_code = CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW;
+ error_message = "Hash does not meet difficulty (could be wrong PoW hash, or mining at lower difficulty than required, or attempt to defraud)";
+ sub64clamp(&info.credits, PENALTY_FOR_BAD_HASH * m_credits_per_hash_found);
+ return false;
+ }
+
+ add64clamp(&info.credits, m_credits_per_hash_found);
+ MINFO("client " << client << " credited for " << m_credits_per_hash_found << ", now " << info.credits << (is_current ? "" : " (close)"));
+
+ m_hashrate[now] += m_diff;
+ add64clamp(&m_credits_total, m_credits_per_hash_found);
+ add64clamp(&info.credits_total, m_credits_per_hash_found);
+ ++m_nonces_good;
+ ++info.nonces_good;
+
+ credits = info.credits;
+ block = info.block;
+ block.nonce = nonce;
+ stale = !is_current;
+ return true;
+ }
+
+ bool rpc_payment::foreach(const std::function<bool(const crypto::public_key &client, const client_info &info)> &f) const
+ {
+ for (std::unordered_map<crypto::public_key, client_info>::const_iterator i = m_client_info.begin(); i != m_client_info.end(); ++i)
+ {
+ if (!f(i->first, i->second))
+ return false;
+ }
+ return true;
+ }
+
+ bool rpc_payment::load(std::string directory)
+ {
+ TRY_ENTRY();
+ m_directory = std::move(directory);
+ std::string state_file_path = directory + "/" + RPC_PAYMENTS_DATA_FILENAME;
+ MINFO("loading rpc payments data from " << state_file_path);
+ std::ifstream data;
+ data.open(state_file_path, std::ios_base::binary | std::ios_base::in);
+ if (!data.fail())
+ {
+ try
+ {
+ boost::archive::portable_binary_iarchive a(data);
+ a >> *this;
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Failed to load RPC payments file: " << e.what());
+ m_client_info.clear();
+ }
+ }
+ else
+ {
+ m_client_info.clear();
+ }
+
+ CATCH_ENTRY_L0("rpc_payment::load", false);
+ return true;
+ }
+
+ bool rpc_payment::store(const std::string &directory_) const
+ {
+ TRY_ENTRY();
+ const std::string &directory = directory_.empty() ? m_directory : directory_;
+ MDEBUG("storing rpc payments data to " << directory);
+ if (!tools::create_directories_if_necessary(directory))
+ {
+ MWARNING("Failed to create data directory: " << directory);
+ return false;
+ }
+ const boost::filesystem::path state_file_path = (boost::filesystem::path(directory) / RPC_PAYMENTS_DATA_FILENAME);
+ if (boost::filesystem::exists(state_file_path))
+ {
+ std::string state_file_path_old = state_file_path.string() + ".old";
+ boost::system::error_code ec;
+ boost::filesystem::remove(state_file_path_old, ec);
+ std::error_code e = tools::replace_file(state_file_path.string(), state_file_path_old);
+ if (e)
+ MWARNING("Failed to rename " << state_file_path << " to " << state_file_path_old << ": " << e);
+ }
+ std::ofstream data;
+ data.open(state_file_path.string(), std::ios_base::binary | std::ios_base::out | std::ios::trunc);
+ if (data.fail())
+ {
+ MWARNING("Failed to save RPC payments to file " << state_file_path);
+ return false;
+ };
+ boost::archive::portable_binary_oarchive a(data);
+ a << *this;
+ return true;
+ CATCH_ENTRY_L0("rpc_payment::store", false);
+ }
+
+ unsigned int rpc_payment::flush_by_age(time_t seconds)
+ {
+ unsigned int count = 0;
+ const time_t now = time(NULL);
+ time_t seconds0 = seconds;
+ if (seconds == 0)
+ {
+ seconds = DEFAULT_FLUSH_AGE;
+ seconds0 = DEFAULT_ZERO_FLUSH_AGE;
+ }
+ const time_t threshold = seconds > now ? 0 : now - seconds;
+ const time_t threshold0 = seconds0 > now ? 0 : now - seconds0;
+ for (std::unordered_map<crypto::public_key, client_info>::iterator i = m_client_info.begin(); i != m_client_info.end(); )
+ {
+ std::unordered_map<crypto::public_key, client_info>::iterator j = i++;
+ const time_t t = std::max(j->second.last_request_timestamp, j->second.update_time);
+ const bool erase = t < ((j->second.credits == 0) ? threshold0 : threshold);
+ if (erase)
+ {
+ MINFO("Erasing " << j->first << " with " << j->second.credits << " credits, inactive for " << (now-t)/86400 << " days");
+ m_client_info.erase(j);
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ uint64_t rpc_payment::get_hashes(unsigned int seconds) const
+ {
+ const uint64_t now = time(NULL);
+ uint64_t hashes = 0;
+ for (std::map<uint64_t, uint64_t>::const_reverse_iterator i = m_hashrate.crbegin(); i != m_hashrate.crend(); ++i)
+ {
+ if (now > i->first + seconds)
+ break;
+ hashes += i->second;
+ }
+ return hashes;
+ }
+
+ void rpc_payment::prune_hashrate(unsigned int seconds)
+ {
+ const uint64_t now = time(NULL);
+ std::map<uint64_t, uint64_t>::iterator i;
+ for (i = m_hashrate.begin(); i != m_hashrate.end(); ++i)
+ {
+ if (now <= i->first + seconds)
+ break;
+ }
+ m_hashrate.erase(m_hashrate.begin(), i);
+ }
+
+ bool rpc_payment::on_idle()
+ {
+ flush_by_age();
+ prune_hashrate(3600);
+ return true;
+ }
+}
diff --git a/src/rpc/rpc_payment.h b/src/rpc/rpc_payment.h
new file mode 100644
index 000000000..f6832fd34
--- /dev/null
+++ b/src/rpc/rpc_payment.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2018-2019, 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.
+
+#pragma once
+
+#include <string>
+#include <unordered_set>
+#include <unordered_map>
+#include <boost/serialization/version.hpp>
+#include "cryptonote_basic/blobdatatype.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+
+namespace cryptonote
+{
+ class rpc_payment
+ {
+ public:
+ struct client_info
+ {
+ cryptonote::block block;
+ cryptonote::block previous_block;
+ cryptonote::blobdata hashing_blob;
+ cryptonote::blobdata previous_hashing_blob;
+ uint64_t previous_seed_height;
+ uint64_t seed_height;
+ crypto::hash previous_seed_hash;
+ crypto::hash seed_hash;
+ uint32_t cookie;
+ crypto::hash top;
+ crypto::hash previous_top;
+ uint64_t credits;
+ std::unordered_set<uint64_t> payments;
+ std::unordered_set<uint64_t> previous_payments;
+ uint64_t update_time;
+ uint64_t last_request_timestamp;
+ uint64_t block_template_update_time;
+ uint64_t credits_total;
+ uint64_t credits_used;
+ uint64_t nonces_good;
+ uint64_t nonces_stale;
+ uint64_t nonces_bad;
+ uint64_t nonces_dupe;
+
+ client_info();
+
+ template <class t_archive>
+ inline void serialize(t_archive &a, const unsigned int ver)
+ {
+ a & block;
+ a & previous_block;
+ a & hashing_blob;
+ a & previous_hashing_blob;
+ a & seed_height;
+ a & previous_seed_height;
+ a & seed_hash;
+ a & previous_seed_hash;
+ a & cookie;
+ a & top;
+ a & previous_top;
+ a & credits;
+ a & payments;
+ a & previous_payments;
+ a & update_time;
+ a & last_request_timestamp;
+ a & block_template_update_time;
+ a & credits_total;
+ a & credits_used;
+ a & nonces_good;
+ a & nonces_stale;
+ a & nonces_bad;
+ a & nonces_dupe;
+ }
+ };
+
+ public:
+ rpc_payment(const cryptonote::account_public_address &address, uint64_t diff, uint64_t credits_per_hash_found);
+ uint64_t balance(const crypto::public_key &client, int64_t delta = 0);
+ bool pay(const crypto::public_key &client, uint64_t ts, uint64_t payment, const std::string &rpc, bool same_ts, uint64_t &credits);
+ bool get_info(const crypto::public_key &client, const std::function<bool(const cryptonote::blobdata&, cryptonote::block&, uint64_t &seed_height, crypto::hash &seed_hash)> &get_block_template, cryptonote::blobdata &hashing_blob, uint64_t &seed_height, crypto::hash &seed_hash, const crypto::hash &top, uint64_t &diff, uint64_t &credits_per_hash_found, uint64_t &credits, uint32_t &cookie);
+ bool submit_nonce(const crypto::public_key &client, uint32_t nonce, const crypto::hash &top, int64_t &error_code, std::string &error_message, uint64_t &credits, crypto::hash &hash, cryptonote::block &block, uint32_t cookie, bool &stale);
+ const cryptonote::account_public_address &get_payment_address() const { return m_address; }
+ bool foreach(const std::function<bool(const crypto::public_key &client, const client_info &info)> &f) const;
+ unsigned int flush_by_age(time_t seconds = 0);
+ uint64_t get_hashes(unsigned int seconds) const;
+ void prune_hashrate(unsigned int seconds);
+ bool on_idle();
+
+ template <class t_archive>
+ inline void serialize(t_archive &a, const unsigned int ver)
+ {
+ a & m_client_info;
+ a & m_hashrate;
+ a & m_credits_total;
+ a & m_credits_used;
+ a & m_nonces_good;
+ a & m_nonces_stale;
+ a & m_nonces_bad;
+ a & m_nonces_dupe;
+ }
+
+ bool load(std::string directory);
+ bool store(const std::string &directory = std::string()) const;
+
+ private:
+ cryptonote::account_public_address m_address;
+ uint64_t m_diff;
+ uint64_t m_credits_per_hash_found;
+ std::unordered_map<crypto::public_key, client_info> m_client_info;
+ std::string m_directory;
+ std::map<uint64_t, uint64_t> m_hashrate;
+ uint64_t m_credits_total;
+ uint64_t m_credits_used;
+ uint64_t m_nonces_good;
+ uint64_t m_nonces_stale;
+ uint64_t m_nonces_bad;
+ uint64_t m_nonces_dupe;
+ };
+}
+
+BOOST_CLASS_VERSION(cryptonote::rpc_payment, 0);
+BOOST_CLASS_VERSION(cryptonote::rpc_payment::client_info, 0);
diff --git a/src/rpc/rpc_payment_costs.h b/src/rpc/rpc_payment_costs.h
new file mode 100644
index 000000000..3b27bf286
--- /dev/null
+++ b/src/rpc/rpc_payment_costs.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2019, 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.
+
+#pragma once
+
+#define COST_PER_BLOCK 0.05
+#define COST_PER_TX_RELAY 100
+#define COST_PER_OUT 1
+#define COST_PER_OUTPUT_INDEXES 1
+#define COST_PER_TX 0.5
+#define COST_PER_KEY_IMAGE 0.01
+#define COST_PER_POOL_HASH 0.01
+#define COST_PER_TX_POOL_STATS 0.2
+#define COST_PER_BLOCK_HEADER 0.1
+#define COST_PER_GET_INFO 1
+#define COST_PER_OUTPUT_HISTOGRAM 25000
+#define COST_PER_FULL_OUTPUT_HISTOGRAM 5000000
+#define COST_PER_OUTPUT_DISTRIBUTION_0 20
+#define COST_PER_OUTPUT_DISTRIBUTION 50000
+#define COST_PER_COINBASE_TX_SUM_BLOCK 2
+#define COST_PER_BLOCK_HASH 0.002
+#define COST_PER_FEE_ESTIMATE 1
+#define COST_PER_SYNC_INFO 2
+#define COST_PER_HARD_FORK_INFO 1
+#define COST_PER_PEER_LIST 2
diff --git a/src/rpc/rpc_payment_signature.cpp b/src/rpc/rpc_payment_signature.cpp
new file mode 100644
index 000000000..159bb5730
--- /dev/null
+++ b/src/rpc/rpc_payment_signature.cpp
@@ -0,0 +1,107 @@
+// Copyright (c) 2018-2019, 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.
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <chrono>
+#include "include_base_utils.h"
+#include "string_tools.h"
+#include "rpc_payment_signature.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.payment"
+
+#define TIMESTAMP_LEEWAY (60 * 1000000) /* 60 seconds, in microseconds */
+
+namespace cryptonote
+{
+ std::string make_rpc_payment_signature(const crypto::secret_key &skey)
+ {
+ std::string s;
+ crypto::public_key pkey;
+ crypto::secret_key_to_public_key(skey, pkey);
+ crypto::signature sig;
+ const uint64_t now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
+ char ts[17];
+ int ret = snprintf(ts, sizeof(ts), "%16.16" PRIx64, now);
+ CHECK_AND_ASSERT_MES(ret == 16, "", "snprintf failed");
+ ts[16] = 0;
+ CHECK_AND_ASSERT_MES(strlen(ts) == 16, "", "Invalid time conversion");
+ crypto::hash hash;
+ crypto::cn_fast_hash(ts, 16, hash);
+ crypto::generate_signature(hash, pkey, skey, sig);
+ s = epee::string_tools::pod_to_hex(pkey) + ts + epee::string_tools::pod_to_hex(sig);
+ return s;
+ }
+
+ bool verify_rpc_payment_signature(const std::string &message, crypto::public_key &pkey, uint64_t &ts)
+ {
+ if (message.size() != 2 * sizeof(crypto::public_key) + 16 + 2 * sizeof(crypto::signature))
+ {
+ MDEBUG("Bad message size: " << message.size());
+ return false;
+ }
+ const std::string pkey_string = message.substr(0, 2 * sizeof(crypto::public_key));
+ const std::string ts_string = message.substr(2 * sizeof(crypto::public_key), 16);
+ const std::string signature_string = message.substr(2 * sizeof(crypto::public_key) + 16);
+ if (!epee::string_tools::hex_to_pod(pkey_string, pkey))
+ {
+ MDEBUG("Bad client id");
+ return false;
+ }
+ crypto::signature signature;
+ if (!epee::string_tools::hex_to_pod(signature_string, signature))
+ {
+ MDEBUG("Bad signature");
+ return false;
+ }
+ crypto::hash hash;
+ crypto::cn_fast_hash(ts_string.data(), 16, hash);
+ if (!crypto::check_signature(hash, pkey, signature))
+ {
+ MDEBUG("signature does not verify");
+ return false;
+ }
+ char *endptr = NULL;
+ errno = 0;
+ unsigned long long ull = strtoull(ts_string.c_str(), &endptr, 16);
+ if (ull == ULLONG_MAX && errno == ERANGE)
+ {
+ MDEBUG("bad timestamp");
+ return false;
+ }
+ ts = ull;
+ const uint64_t now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
+ if (ts > now + TIMESTAMP_LEEWAY)
+ {
+ MDEBUG("Timestamp is in the future");
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/rpc/rpc_payment_signature.h b/src/rpc/rpc_payment_signature.h
new file mode 100644
index 000000000..4a2fe2ea3
--- /dev/null
+++ b/src/rpc/rpc_payment_signature.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2018-2019, 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.
+
+#pragma once
+
+#include <stdint.h>
+#include <string>
+#include "crypto/crypto.h"
+
+namespace cryptonote
+{
+ std::string make_rpc_payment_signature(const crypto::secret_key &skey);
+ bool verify_rpc_payment_signature(const std::string &message, crypto::public_key &pkey, uint64_t &ts);
+}