aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h6
-rw-r--r--src/cryptonote_core/cryptonote_basic.h4
-rw-r--r--src/daemon/command_parser_executor.cpp29
-rw-r--r--src/daemon/command_parser_executor.h6
-rw-r--r--src/daemon/command_server.cpp15
-rw-r--r--src/daemon/rpc_command_executor.cpp110
-rw-r--r--src/daemon/rpc_command_executor.h6
-rw-r--r--src/p2p/net_node.h4
-rw-r--r--src/p2p/net_node.inl18
-rw-r--r--src/p2p/net_node_common.h14
-rw-r--r--src/rpc/core_rpc_server.cpp52
-rw-r--r--src/rpc/core_rpc_server.h30
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h66
-rw-r--r--src/wallet/wallet2.cpp134
-rw-r--r--src/wallet/wallet2.h8
15 files changed, 453 insertions, 49 deletions
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index f812077f1..a822cce3e 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -55,8 +55,8 @@
#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
-#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) \
- else if(query_info.m_URI == s_pattern) \
+#define MAP_URI_AUTO_JON2_IF(s_pattern, callback_f, command_type, cond) \
+ else if((query_info.m_URI == s_pattern) && (cond)) \
{ \
handled = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
@@ -80,6 +80,8 @@
LOG_PRINT( s_pattern << " processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
}
+#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) MAP_URI_AUTO_JON2_IF(s_pattern, callback_f, command_type, true)
+
#define MAP_URI_AUTO_BIN2(s_pattern, callback_f, command_type) \
else if(query_info.m_URI == s_pattern) \
{ \
diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h
index 94887b5a0..aa8ba4f39 100644
--- a/src/cryptonote_core/cryptonote_basic.h
+++ b/src/cryptonote_core/cryptonote_basic.h
@@ -284,8 +284,8 @@ namespace cryptonote
uint32_t nonce;
BEGIN_SERIALIZE()
- VARINT_FIELD(major_version)
- VARINT_FIELD(minor_version)
+ FIELD(major_version)
+ FIELD(minor_version)
VARINT_FIELD(timestamp)
FIELD(prev_id)
FIELD(nonce)
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index a07bb25de..487d86071 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -392,5 +392,34 @@ bool t_command_parser_executor::hard_fork_info(const std::vector<std::string>& a
return m_executor.hard_fork_info(version);
}
+bool t_command_parser_executor::show_bans(const std::vector<std::string>& args)
+{
+ if (!args.empty()) return false;
+ return m_executor.print_bans();
+}
+
+bool t_command_parser_executor::ban(const std::vector<std::string>& args)
+{
+ if (args.size() != 1 && args.size() != 2) return false;
+ std::string ip = args[0];
+ time_t seconds = P2P_IP_BLOCKTIME;
+ if (args.size() > 1)
+ {
+ seconds = std::stoi(args[0]);
+ if (seconds == 0)
+ {
+ return false;
+ }
+ }
+ return m_executor.ban(ip, seconds);
+}
+
+bool t_command_parser_executor::unban(const std::vector<std::string>& args)
+{
+ if (args.size() != 1) return false;
+ std::string ip = args[0];
+ return m_executor.unban(ip);
+}
+
} // namespace daemonize
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index f00fbd77e..0c042cd5d 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -106,6 +106,12 @@ public:
bool stop_save_graph(const std::vector<std::string>& args);
bool hard_fork_info(const std::vector<std::string>& args);
+
+ bool show_bans(const std::vector<std::string>& args);
+
+ bool ban(const std::vector<std::string>& args);
+
+ bool unban(const std::vector<std::string>& args);
};
} // namespace daemonize
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 8714b2569..0999ed30c 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -194,6 +194,21 @@ t_command_server::t_command_server(
, std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1)
, "Print hard fork voting information"
);
+ m_command_lookup.set_handler(
+ "bans"
+ , std::bind(&t_command_parser_executor::show_bans, &m_parser, p::_1)
+ , "Show the currently banned IPs"
+ );
+ m_command_lookup.set_handler(
+ "ban"
+ , std::bind(&t_command_parser_executor::ban, &m_parser, p::_1)
+ , "Ban a given IP for a time"
+ );
+ m_command_lookup.set_handler(
+ "unban"
+ , std::bind(&t_command_parser_executor::unban, &m_parser, p::_1)
+ , "Unban a given IP"
+ );
}
bool t_command_server::process_command_str(const std::string& cmd)
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 176df81fc..74dbc0012 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -242,7 +242,7 @@ bool t_rpc_command_executor::show_difficulty() {
tools::success_msg_writer() << "BH: " << res.height
<< ", DIFF: " << res.difficulty
- << ", HR: " << (int) res.difficulty / 60L << " H/s";
+ << ", HR: " << (int) res.difficulty / res.target << " H/s";
return true;
}
@@ -287,7 +287,7 @@ bool t_rpc_command_executor::show_status() {
% (100.0f * ires.height / (ires.target_height ? ires.target_height < ires.height ? ires.height : ires.target_height : ires.height))
% (ires.testnet ? "testnet" : "mainnet")
% [&ires]()->std::string {
- float hr = ires.difficulty / 60.0f;
+ float hr = ires.difficulty / ires.target;
if (hr>1e9) return (boost::format("%.2f GH/s") % (hr/1e9)).str();
if (hr>1e6) return (boost::format("%.2f MH/s") % (hr/1e6)).str();
if (hr>1e3) return (boost::format("%.2f kH/s") % (hr/1e3)).str();
@@ -1036,4 +1036,110 @@ bool t_rpc_command_executor::hard_fork_info(uint8_t version)
return true;
}
+bool t_rpc_command_executor::print_bans()
+{
+ cryptonote::COMMAND_RPC_GETBANS::request req;
+ cryptonote::COMMAND_RPC_GETBANS::response res;
+ std::string fail_message = "Unsuccessful";
+ epee::json_rpc::error error_resp;
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(req, res, "get_bans", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_bans(req, res, error_resp))
+ {
+ tools::fail_msg_writer() << fail_message.c_str();
+ return true;
+ }
+ }
+
+ time_t now = time(nullptr);
+ for (auto i = res.bans.begin(); i != res.bans.end(); ++i)
+ {
+ time_t seconds = i->seconds - now;
+ tools::msg_writer() << epee::string_tools::get_ip_string_from_int32(i->ip) << " banned for " << seconds << " seconds";
+ }
+
+ return true;
+}
+
+
+bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds)
+{
+ cryptonote::COMMAND_RPC_SETBANS::request req;
+ cryptonote::COMMAND_RPC_SETBANS::response res;
+ std::string fail_message = "Unsuccessful";
+ epee::json_rpc::error error_resp;
+
+ cryptonote::COMMAND_RPC_SETBANS::ban ban;
+ if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip))
+ {
+ tools::fail_msg_writer() << "Invalid IP";
+ return true;
+ }
+ ban.ban = true;
+ ban.seconds = seconds;
+ req.bans.push_back(ban);
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(req, res, "set_bans", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_set_bans(req, res, error_resp))
+ {
+ tools::fail_msg_writer() << fail_message.c_str();
+ return true;
+ }
+ }
+
+ return true;
+}
+
+bool t_rpc_command_executor::unban(const std::string &ip)
+{
+ cryptonote::COMMAND_RPC_SETBANS::request req;
+ cryptonote::COMMAND_RPC_SETBANS::response res;
+ std::string fail_message = "Unsuccessful";
+ epee::json_rpc::error error_resp;
+
+ cryptonote::COMMAND_RPC_SETBANS::ban ban;
+ if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip))
+ {
+ tools::fail_msg_writer() << "Invalid IP";
+ return true;
+ }
+ ban.ban = false;
+ ban.seconds = 0;
+ req.bans.push_back(ban);
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(req, res, "set_bans", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_set_bans(req, res, error_resp))
+ {
+ tools::fail_msg_writer() << fail_message.c_str();
+ return true;
+ }
+ }
+
+ return true;
+}
+
}// namespace daemonize
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 778b73acb..95c5624fa 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -124,6 +124,12 @@ public:
bool stop_save_graph();
bool hard_fork_info(uint8_t version);
+
+ bool print_bans();
+
+ bool ban(const std::string &ip, time_t seconds);
+
+ bool unban(const std::string &ip);
};
} // namespace daemonize
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 4aaac813e..39cbe01fa 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -117,6 +117,9 @@ namespace nodetool
size_t get_outgoing_connections_count();
peerlist_manager& get_peerlist_manager(){return m_peerlist;}
void delete_connections(size_t count);
+ virtual bool block_ip(uint32_t adress, time_t seconds = P2P_IP_BLOCKTIME);
+ virtual bool unblock_ip(uint32_t address);
+ virtual std::map<uint32_t, time_t> get_blocked_ips() const { return m_blocked_ips; }
private:
const std::vector<std::string> m_seed_nodes_list =
{ "seeds.moneroseeds.se"
@@ -171,7 +174,6 @@ namespace nodetool
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
virtual void request_callback(const epee::net_utils::connection_context_base& context);
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f);
- virtual bool block_ip(uint32_t adress);
virtual bool add_ip_fail(uint32_t address);
//----------------- i_connection_filter --------------------------------------------------------
virtual bool is_remote_ip_allowed(uint32_t adress);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 11df7ee49..067f6378d 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -169,7 +169,7 @@ namespace nodetool
auto it = m_blocked_ips.find(addr);
if(it == m_blocked_ips.end())
return true;
- if(time(nullptr) - it->second > P2P_IP_BLOCKTIME )
+ if(time(nullptr) >= it->second)
{
m_blocked_ips.erase(it);
LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << "is unblocked.", LOG_LEVEL_0);
@@ -186,15 +186,27 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::block_ip(uint32_t addr)
+ bool node_server<t_payload_net_handler>::block_ip(uint32_t addr, time_t seconds)
{
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
- m_blocked_ips[addr] = time(nullptr);
+ m_blocked_ips[addr] = time(nullptr) + seconds;
LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.", LOG_LEVEL_0);
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::unblock_ip(uint32_t addr)
+ {
+ CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
+ auto i = m_blocked_ips.find(addr);
+ if (i == m_blocked_ips.end())
+ return false;
+ m_blocked_ips.erase(i);
+ LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.", LOG_LEVEL_0);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::add_ip_fail(uint32_t address)
{
CRITICAL_REGION_LOCAL(m_ip_fails_score_lock);
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 93b29deb2..2505006ad 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -50,7 +50,9 @@ namespace nodetool
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_connections_count()=0;
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type)> f)=0;
- virtual bool block_ip(uint32_t adress)=0;
+ virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0;
+ virtual bool unblock_ip(uint32_t adress)=0;
+ virtual std::map<uint32_t, time_t> get_blocked_ips()const=0;
virtual bool add_ip_fail(uint32_t adress)=0;
};
@@ -86,10 +88,18 @@ namespace nodetool
{
return false;
}
- virtual bool block_ip(uint32_t adress)
+ virtual bool block_ip(uint32_t adress, time_t seconds)
{
return true;
}
+ virtual bool unblock_ip(uint32_t adress)
+ {
+ return true;
+ }
+ virtual std::map<uint32_t, time_t> get_blocked_ips() const
+ {
+ return std::map<uint32_t, time_t>();
+ }
virtual bool add_ip_fail(uint32_t adress)
{
return true;
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index f5e700033..4ba3acc37 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -51,6 +51,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_rpc_bind_ip);
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_testnet_rpc_bind_port);
+ command_line::add_arg(desc, arg_restricted_rpc);
}
//------------------------------------------------------------------------------------------------------------------------------
core_rpc_server::core_rpc_server(
@@ -69,6 +70,7 @@ namespace cryptonote
m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
m_port = command_line::get_arg(vm, p2p_bind_arg);
+ m_restricted = command_line::get_arg(vm, arg_restricted_rpc);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -119,6 +121,7 @@ namespace cryptonote
res.height = m_core.get_current_blockchain_height();
res.target_height = m_core.get_target_blockchain_height();
res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
+ res.target = m_core.get_blockchain_storage().get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET;
res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
res.tx_pool_size = m_core.get_pool_transactions_count();
res.alt_blocks_count = m_core.get_blockchain_storage().get_alternative_blocks_count();
@@ -899,6 +902,49 @@ namespace cryptonote
#endif
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp)
+ {
+ if(!check_core_busy())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
+ error_resp.message = "Core is busy.";
+ return false;
+ }
+
+ std::map<uint32_t, time_t> blocked_ips = m_p2p.get_blocked_ips();
+ for (std::map<uint32_t, time_t>::const_iterator i = blocked_ips.begin(); i != blocked_ips.end(); ++i)
+ {
+ COMMAND_RPC_GETBANS::ban b;
+ b.ip = i->first;
+ b.seconds = i->second;
+ res.bans.push_back(b);
+ }
+
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp)
+ {
+ if(!check_core_busy())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
+ error_resp.message = "Core is busy.";
+ return false;
+ }
+
+ for (auto i = req.bans.begin(); i != req.bans.end(); ++i)
+ {
+ if (i->ban)
+ m_p2p.block_ip(i->ip, i->seconds);
+ else
+ m_p2p.unblock_ip(i->ip);
+ }
+
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_fast_exit(const COMMAND_RPC_FAST_EXIT::request& req, COMMAND_RPC_FAST_EXIT::response& res)
{
cryptonote::core::set_fast_exit();
@@ -957,4 +1003,10 @@ namespace cryptonote
, std::to_string(config::testnet::RPC_DEFAULT_PORT)
};
+ const command_line::arg_descriptor<bool> core_rpc_server::arg_restricted_rpc = {
+ "restricted-rpc"
+ , "Restrict RPC to view only commands"
+ , false
+ };
+
} // namespace cryptonote
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 1fbd0981f..8fe17ff5d 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -55,6 +55,7 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
static const command_line::arg_descriptor<std::string> arg_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port;
+ static const command_line::arg_descriptor<bool> arg_restricted_rpc;
typedef epee::net_utils::connection_context_base connection_context;
@@ -79,20 +80,20 @@ namespace cryptonote
MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS)
MAP_URI_AUTO_JON2("/is_key_image_spent", on_is_key_image_spent, COMMAND_RPC_IS_KEY_IMAGE_SPENT)
MAP_URI_AUTO_JON2("/sendrawtransaction", on_send_raw_tx, COMMAND_RPC_SEND_RAW_TX)
- MAP_URI_AUTO_JON2("/start_mining", on_start_mining, COMMAND_RPC_START_MINING)
- MAP_URI_AUTO_JON2("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING)
- MAP_URI_AUTO_JON2("/mining_status", on_mining_status, COMMAND_RPC_MINING_STATUS)
- MAP_URI_AUTO_JON2("/save_bc", on_save_bc, COMMAND_RPC_SAVE_BC)
- MAP_URI_AUTO_JON2("/get_peer_list", on_get_peer_list, COMMAND_RPC_GET_PEER_LIST)
- MAP_URI_AUTO_JON2("/set_log_hash_rate", on_set_log_hash_rate, COMMAND_RPC_SET_LOG_HASH_RATE)
- MAP_URI_AUTO_JON2("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL)
+ MAP_URI_AUTO_JON2_IF("/start_mining", on_start_mining, COMMAND_RPC_START_MINING, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/mining_status", on_mining_status, COMMAND_RPC_MINING_STATUS, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/save_bc", on_save_bc, COMMAND_RPC_SAVE_BC, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/get_peer_list", on_get_peer_list, COMMAND_RPC_GET_PEER_LIST, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/set_log_hash_rate", on_set_log_hash_rate, COMMAND_RPC_SET_LOG_HASH_RATE, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL, !m_restricted)
MAP_URI_AUTO_JON2("/get_transaction_pool", on_get_transaction_pool, COMMAND_RPC_GET_TRANSACTION_POOL)
- MAP_URI_AUTO_JON2("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON)
+ MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
- MAP_URI_AUTO_JON2("/fast_exit", on_fast_exit, COMMAND_RPC_FAST_EXIT)
- MAP_URI_AUTO_JON2("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS)
- MAP_URI_AUTO_JON2("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH)
- MAP_URI_AUTO_JON2("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH)
+ MAP_URI_AUTO_JON2_IF("/fast_exit", on_fast_exit, COMMAND_RPC_FAST_EXIT, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
BEGIN_JSON_RPC_MAP("/json_rpc")
MAP_JON_RPC("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT)
MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH)
@@ -105,6 +106,8 @@ namespace cryptonote
MAP_JON_RPC_WE("get_connections", on_get_connections, COMMAND_RPC_GET_CONNECTIONS)
MAP_JON_RPC_WE("get_info", on_get_info_json, COMMAND_RPC_GET_INFO)
MAP_JON_RPC_WE("hard_fork_info", on_hard_fork_info, COMMAND_RPC_HARD_FORK_INFO)
+ MAP_JON_RPC_WE("setbans", on_set_bans, COMMAND_RPC_SETBANS)
+ MAP_JON_RPC_WE("getbans", on_get_bans, COMMAND_RPC_GETBANS)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -142,6 +145,8 @@ namespace cryptonote
bool on_get_connections(const COMMAND_RPC_GET_CONNECTIONS::request& req, COMMAND_RPC_GET_CONNECTIONS::response& res, epee::json_rpc::error& error_resp);
bool on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp);
bool 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);
+ bool on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp);
+ bool on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp);
//-----------------------
private:
@@ -161,5 +166,6 @@ private:
std::string m_port;
std::string m_bind_ip;
bool m_testnet;
+ bool m_restricted;
};
}
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index aa88ffcb4..b70164614 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -273,6 +273,7 @@ namespace cryptonote
uint64_t height;
uint64_t target_height;
uint64_t difficulty;
+ uint64_t target;
uint64_t tx_count;
uint64_t tx_pool_size;
uint64_t alt_blocks_count;
@@ -888,5 +889,70 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
};
+
+ struct COMMAND_RPC_GETBANS
+ {
+ struct ban
+ {
+ uint32_t ip;
+ uint32_t seconds;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(ip)
+ KV_SERIALIZE(seconds)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+ std::vector<ban> bans;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(bans)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_SETBANS
+ {
+ struct ban
+ {
+ uint32_t ip;
+ bool ban;
+ uint32_t seconds;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(ip)
+ KV_SERIALIZE(ban)
+ KV_SERIALIZE(seconds)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct request
+ {
+ std::vector<ban> bans;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(bans)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index a5a1e5977..8a172be90 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -203,31 +203,64 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
tx_pub_key = pub_key_field.pub_key;
bool r = true;
- int threads;
+ int threads = std::thread::hardware_concurrency();
if (miner_tx && m_refresh_type == RefreshNoCoinbase)
{
// assume coinbase isn't for us
}
else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase)
{
- for (size_t i = 0; i < tx.vout.size(); ++i)
+ uint64_t money_transfered = 0;
+ bool error = false;
+ check_acc_out(m_account.get_keys(), tx.vout[0], tx_pub_key, 0, money_transfered, error);
+ if (error)
{
- uint64_t money_transfered = 0;
- bool error = false;
- check_acc_out(m_account.get_keys(), tx.vout[i], tx_pub_key, i, money_transfered, error);
- if (error)
+ r = false;
+ }
+ else
+ {
+ // this assumes that the miner tx pays a single address
+ if (money_transfered > 0)
{
- r = false;
- break;
+ outs.push_back(0);
+ tx_money_got_in_outs = money_transfered;
+
+ // process the other outs from that tx
+ boost::asio::io_service ioservice;
+ boost::thread_group threadpool;
+ std::auto_ptr < boost::asio::io_service::work > work(new boost::asio::io_service::work(ioservice));
+ for (int i = 0; i < threads; i++)
+ {
+ threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice));
+ }
+
+ const account_keys &keys = m_account.get_keys();
+ std::vector<uint64_t> money_transfered(tx.vout.size());
+ std::deque<bool> error(tx.vout.size());
+ // the first one was already checked
+ for (size_t i = 1; i < tx.vout.size(); ++i)
+ {
+ ioservice.dispatch(boost::bind(&wallet2::check_acc_out, this, std::cref(keys), std::cref(tx.vout[i]), std::cref(tx_pub_key), i,
+ std::ref(money_transfered[i]), std::ref(error[i])));
+ }
+ KILL_IOSERVICE();
+ for (size_t i = 1; i < tx.vout.size(); ++i)
+ {
+ if (error[i])
+ {
+ r = false;
+ break;
+ }
+ if (money_transfered[i])
+ {
+ outs.push_back(i);
+ tx_money_got_in_outs += money_transfered[i];
+ }
+ }
}
- // this assumes that the miner tx pays a single address
- if (money_transfered == 0)
- break;
- outs.push_back(i);
- tx_money_got_in_outs += money_transfered;
}
}
- else if (tx.vout.size() > 1 && (threads = std::thread::hardware_concurrency()) > 1)
+ else if (tx.vout.size() > 1 && threads > 1)
{
boost::asio::io_service ioservice;
boost::thread_group threadpool;
@@ -274,7 +307,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
cryptonote::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res);
req.txid = get_transaction_hash(tx);
+ m_daemon_rpc_mutex.lock();
bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/get_o_indexes.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT);
+ m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_o_indexes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_o_indexes.bin");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_out_indices_error, res.status);
@@ -478,19 +513,28 @@ void wallet2::parse_block_round(const cryptonote::blobdata &blob, cryptonote::bl
bl_id = get_block_hash(bl);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::pull_blocks(uint64_t start_height, uint64_t& blocks_added)
+void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::list<cryptonote::block_complete_entry> &blocks)
{
- blocks_added = 0;
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
- get_short_chain_history(req.block_ids);
+ req.block_ids = short_chain_history;
+
req.start_height = start_height;
+ m_daemon_rpc_mutex.lock();
bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getblocks.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT);
+ m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblocks.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblocks.bin");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, res.status);
- size_t current_index = res.start_height;
+ blocks_start_height = res.start_height;
+ blocks = res.blocks;
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote::block_complete_entry> &blocks, uint64_t& blocks_added)
+{
+ size_t current_index = start_height;
+ blocks_added = 0;
int threads = std::thread::hardware_concurrency();
if (threads > 1)
@@ -498,7 +542,6 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t& blocks_added)
std::vector<crypto::hash> round_block_hashes(threads);
std::vector<cryptonote::block> round_blocks(threads);
std::deque<bool> error(threads);
- const std::list<block_complete_entry> &blocks = res.blocks;
size_t blocks_size = blocks.size();
std::list<block_complete_entry>::const_iterator blocki = blocks.begin();
for (size_t b = 0; b < blocks_size; b += threads)
@@ -559,10 +602,10 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t& blocks_added)
}
else
{
- BOOST_FOREACH(auto& bl_entry, res.blocks)
+ BOOST_FOREACH(auto& bl_entry, blocks)
{
cryptonote::block bl;
- r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl);
+ bool r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl);
THROW_WALLET_EXCEPTION_IF(!r, error::block_parse_error, bl_entry.block);
crypto::hash bl_id = get_block_hash(bl);
@@ -574,9 +617,9 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t& blocks_added)
else if(bl_id != m_blockchain[current_index])
{
//split detected here !!!
- THROW_WALLET_EXCEPTION_IF(current_index == res.start_height, error::wallet_internal_error,
+ THROW_WALLET_EXCEPTION_IF(current_index == start_height, error::wallet_internal_error,
"wrong daemon response: split starts from the first block in response " + string_tools::pod_to_hex(bl_id) +
- " (height " + std::to_string(res.start_height) + "), local block id at this height: " +
+ " (height " + std::to_string(start_height) + "), local block id at this height: " +
string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index);
@@ -604,6 +647,23 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched)
refresh(start_height, blocks_fetched, received_money);
}
//----------------------------------------------------------------------------------------------------
+void wallet2::pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::list<cryptonote::block_complete_entry> &prev_blocks, std::list<cryptonote::block_complete_entry> &blocks)
+{
+ // prepend the last 3 blocks, should be enough to guard against a block or two's reorg
+ cryptonote::block bl;
+ std::list<cryptonote::block_complete_entry>::const_reverse_iterator i = prev_blocks.rbegin();
+ for (size_t n = 0; n < std::min((size_t)3, prev_blocks.size()); ++n)
+ {
+ bool ok = cryptonote::parse_and_validate_block_from_blob(i->block, bl);
+ THROW_WALLET_EXCEPTION_IF(!ok, error::block_parse_error, i->block);
+ short_chain_history.push_front(cryptonote::get_block_hash(bl));
+ ++i;
+ }
+
+ // pull the new blocks
+ pull_blocks(start_height, blocks_start_height, short_chain_history, blocks);
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{
received_money = false;
@@ -611,15 +671,33 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
uint64_t added_blocks = 0;
size_t try_count = 0;
crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash;
+ std::list<crypto::hash> short_chain_history;
+ std::thread pull_thread;
+ uint64_t blocks_start_height;
+ std::list<cryptonote::block_complete_entry> blocks;
+
+ // pull the first set of blocks
+ get_short_chain_history(short_chain_history);
+ pull_blocks(start_height, blocks_start_height, short_chain_history, blocks);
while(m_run.load(std::memory_order_relaxed))
{
try
{
- pull_blocks(start_height, added_blocks);
+ // pull the next set of blocks while we're processing the current one
+ uint64_t next_blocks_start_height;
+ std::list<cryptonote::block_complete_entry> next_blocks;
+ pull_thread = std::thread([&]{pull_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, next_blocks);});
+
+ process_blocks(blocks_start_height, blocks, added_blocks);
blocks_fetched += added_blocks;
+ pull_thread.join();
if(!added_blocks)
break;
+
+ // switch to the new blocks from the daemon
+ blocks_start_height = next_blocks_start_height;
+ blocks = next_blocks;
}
catch (const std::exception&)
{
@@ -1054,6 +1132,8 @@ bool wallet2::prepare_file_names(const std::string& file_path)
//----------------------------------------------------------------------------------------------------
bool wallet2::check_connection()
{
+ std::lock_guard<std::mutex> lock(m_daemon_rpc_mutex);
+
if(m_http_client.is_connected())
return true;
@@ -1266,7 +1346,9 @@ void wallet2::rescan_spent()
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
req.key_images = key_images;
+ m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/is_key_image_spent", req, daemon_resp, m_http_client, 200000);
+ m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
@@ -1573,7 +1655,9 @@ void wallet2::commit_tx(pending_tx& ptx)
COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
+ m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
+ m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status);
@@ -1761,7 +1845,9 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
req.amounts.push_back(it->amount());
}
+ m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000);
+ m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getrandom_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status);
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 79fd2da49..d6aea182d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -357,7 +357,9 @@ namespace tools
bool is_tx_spendtime_unlocked(uint64_t unlock_time) const;
bool is_transfer_unlocked(const transfer_details& td) const;
bool clear();
- void pull_blocks(uint64_t start_height, uint64_t& blocks_added);
+ void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::list<cryptonote::block_complete_entry> &blocks);
+ void pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::list<cryptonote::block_complete_entry> &prev_blocks, std::list<cryptonote::block_complete_entry> &blocks);
+ void process_blocks(uint64_t start_height, const std::list<cryptonote::block_complete_entry> &blocks, uint64_t& blocks_added);
uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers);
bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const cryptonote::transaction& tx, uint64_t height);
@@ -389,6 +391,8 @@ namespace tools
std::atomic<bool> m_run;
+ std::mutex m_daemon_rpc_mutex;
+
i_wallet2_callback* m_callback;
bool m_testnet;
bool m_restricted;
@@ -566,7 +570,9 @@ namespace tools
req.amounts.push_back(it->amount());
}
+ m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000);
+ m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getrandom_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status);