aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt13
-rw-r--r--README.i18n.md (renamed from README.i18n)0
-rw-r--r--README.md2
-rw-r--r--cmake/FindReadline.cmake66
-rw-r--r--contrib/epee/include/console_handler.h41
-rw-r--r--contrib/epee/include/net/abstract_tcp_server.h5
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h2
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl7
-rw-r--r--contrib/epee/include/net/abstract_tcp_server_cp.inl5
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h2
-rw-r--r--contrib/epee/include/net/levin_client_async.h3
-rw-r--r--contrib/epee/include/net/net_utils_base.h122
-rw-r--r--contrib/epee/include/readline_buffer.h40
-rw-r--r--contrib/epee/include/string_tools.h2
-rw-r--r--contrib/epee/src/CMakeLists.txt7
-rw-r--r--contrib/epee/src/readline_buffer.cpp196
-rw-r--r--src/blockchain_db/blockchain_db.h10
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp15
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h1
-rw-r--r--src/common/command_line.cpp7
-rw-r--r--src/common/password.cpp7
-rw-r--r--src/crypto/crypto.cpp134
-rw-r--r--src/crypto/crypto.h14
-rw-r--r--src/crypto/slow-hash.c29
-rw-r--r--src/cryptonote_basic/CMakeLists.txt6
-rw-r--r--src/cryptonote_basic/miner.cpp38
-rw-r--r--src/cryptonote_core/blockchain.cpp5
-rw-r--r--src/cryptonote_core/blockchain.h1
-rw-r--r--src/cryptonote_core/tx_pool.cpp51
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h4
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl55
-rw-r--r--src/daemon/rpc_command_executor.cpp43
-rw-r--r--src/p2p/net_node.h42
-rw-r--r--src/p2p/net_node.inl215
-rw-r--r--src/p2p/net_node_common.h18
-rw-r--r--src/p2p/net_peerlist.h78
-rw-r--r--src/p2p/net_peerlist_boost_serialization.h35
-rw-r--r--src/p2p/p2p_protocol_defs.h121
-rw-r--r--src/rpc/core_rpc_server.cpp40
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h28
-rw-r--r--src/simplewallet/simplewallet.cpp287
-rw-r--r--src/simplewallet/simplewallet.h4
-rw-r--r--src/wallet/api/wallet.cpp2
-rw-r--r--src/wallet/wallet2.cpp4
-rw-r--r--src/wallet/wallet2.h5
-rw-r--r--src/wallet/wallet_errors.h10
-rw-r--r--tests/core_tests/chaingen.h1
-rw-r--r--tests/unit_tests/hardfork.cpp1
48 files changed, 1509 insertions, 315 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9d6be986..a8060f90c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -655,6 +655,19 @@ endif()
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
+option(USE_READLINE "Build with GNU readline support." ON)
+if(USE_READLINE)
+ find_package(Readline)
+ if(READLINE_FOUND AND GNU_READLINE_FOUND)
+ add_definitions(-DHAVE_READLINE)
+ include_directories(${Readline_INCLUDE_DIR})
+ list(APPEND EXTRA_LIBRARIES ${Readline_LIBRARY})
+ message(STATUS "Found readline library at: ${Readline_ROOT_DIR}")
+ else()
+ message(STATUS "Could not find GNU readline library so building without readline support")
+ endif()
+endif()
+
if(ANDROID)
set(ATOMIC libatomic.a)
endif()
diff --git a/README.i18n b/README.i18n.md
index 755c5cf38..755c5cf38 100644
--- a/README.i18n
+++ b/README.i18n.md
diff --git a/README.md b/README.md
index e6450b53c..4ab203671 100644
--- a/README.md
+++ b/README.md
@@ -364,7 +364,7 @@ monero-wallet-cli, and possibly monerod, if you get crashes refreshing.
## Internationalization
-See [README.i18n](README.i18n).
+See [README.i18n.md](README.i18n.md).
## Using Tor
diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake
new file mode 100644
index 000000000..9ccef7ad8
--- /dev/null
+++ b/cmake/FindReadline.cmake
@@ -0,0 +1,66 @@
+# - Try to find readline include dirs and libraries
+#
+# Usage of this module as follows:
+#
+# find_package(Readline)
+#
+# Variables used by this module, they can change the default behaviour and need
+# to be set before calling find_package:
+#
+# Readline_ROOT_DIR Set this variable to the root installation of
+# readline if the module has problems finding the
+# proper installation path.
+#
+# Variables defined by this module:
+#
+# READLINE_FOUND System has readline, include and lib dirs found
+# GNU_READLINE_FOUND Version of readline found is GNU readline, not libedit!
+# Readline_INCLUDE_DIR The readline include directories.
+# Readline_LIBRARY The readline library.
+
+find_path(Readline_ROOT_DIR
+ NAMES include/readline/readline.h
+ PATHS /opt/local/ /usr/local/ /usr/
+ NO_DEFAULT_PATH
+)
+
+find_path(Readline_INCLUDE_DIR
+ NAMES readline/readline.h
+ PATHS ${Readline_ROOT_DIR}/include
+ NO_DEFAULT_PATH
+)
+
+find_library(Readline_LIBRARY
+ NAMES readline
+ PATHS ${Readline_ROOT_DIR}/lib
+ NO_DEFAULT_PATH
+)
+
+if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
+ set(READLINE_FOUND TRUE)
+else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
+ FIND_LIBRARY(Readline_LIBRARY NAMES readline PATHS Readline_ROOT_DIR)
+ include(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY )
+ MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY)
+endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
+
+mark_as_advanced(
+ Readline_ROOT_DIR
+ Readline_INCLUDE_DIR
+ Readline_LIBRARY
+)
+
+set(CMAKE_REQUIRED_INCLUDES ${Readline_INCLUDE_DIR})
+set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY})
+INCLUDE(CheckCXXSourceCompiles)
+CHECK_CXX_SOURCE_COMPILES(
+"
+#include <stdio.h>
+#include <readline/readline.h>
+int
+main()
+{
+ char * s = rl_copy_text(0, 0);
+}
+" GNU_READLINE_FOUND)
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
index 54e3e966d..bb20faa65 100644
--- a/contrib/epee/include/console_handler.h
+++ b/contrib/epee/include/console_handler.h
@@ -38,6 +38,10 @@
#endif
#include <boost/thread.hpp>
+#ifdef HAVE_READLINE
+ #include "readline_buffer.h"
+#endif
+
namespace epee
{
class async_stdin_reader
@@ -49,6 +53,10 @@ namespace epee
, m_read_status(state_init)
{
m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
+#ifdef HAVE_READLINE
+ m_readline_buffer.start();
+ m_readline_thread = boost::thread(std::bind(&async_stdin_reader::readline_thread_func, this));
+#endif
}
~async_stdin_reader()
@@ -56,6 +64,13 @@ namespace epee
stop();
}
+#ifdef HAVE_READLINE
+ rdln::readline_buffer& get_readline_buffer()
+ {
+ return m_readline_buffer;
+ }
+#endif
+
// Not thread safe. Only one thread can call this method at once.
bool get_line(std::string& line)
{
@@ -98,6 +113,10 @@ namespace epee
m_request_cv.notify_one();
m_reader_thread.join();
+#ifdef HAVE_READLINE
+ m_readline_buffer.stop();
+ m_readline_thread.join();
+#endif
}
}
@@ -174,6 +193,16 @@ namespace epee
return true;
}
+#ifdef HAVE_READLINE
+ void readline_thread_func()
+ {
+ while (m_run.load(std::memory_order_relaxed))
+ {
+ m_readline_buffer.process();
+ }
+ }
+#endif
+
void reader_thread_func()
{
while (true)
@@ -187,7 +216,11 @@ namespace epee
{
if (m_run.load(std::memory_order_relaxed))
{
+#ifdef HAVE_READLINE
+ m_readline_buffer.get_line(line);
+#else
std::getline(std::cin, line);
+#endif
read_ok = !std::cin.eof() && !std::cin.fail();
}
}
@@ -229,6 +262,10 @@ namespace epee
private:
boost::thread m_reader_thread;
std::atomic<bool> m_run;
+#ifdef HAVE_READLINE
+ boost::thread m_readline_thread;
+ rdln::readline_buffer m_readline_buffer;
+#endif
std::string m_line;
bool m_has_read_request;
@@ -277,12 +314,16 @@ namespace epee
{
if (!m_prompt.empty())
{
+#ifdef HAVE_READLINE
+ m_stdin_reader.get_readline_buffer().set_prompt(m_prompt);
+#else
epee::set_console_color(epee::console_color_yellow, true);
std::cout << m_prompt;
if (' ' != m_prompt.back())
std::cout << ' ';
epee::reset_console_color();
std::cout.flush();
+#endif
}
}
diff --git a/contrib/epee/include/net/abstract_tcp_server.h b/contrib/epee/include/net/abstract_tcp_server.h
index 1efd5091c..000305cfa 100644
--- a/contrib/epee/include/net/abstract_tcp_server.h
+++ b/contrib/epee/include/net/abstract_tcp_server.h
@@ -296,7 +296,7 @@ namespace net_utils
}
//----------------------------------------------------------------------------------------
template<class THandler>
- bool abstract_tcp_server<THandler>::invoke_connection(SOCKET hnew_sock, long ip_from, int post_from)
+ bool abstract_tcp_server<THandler>::invoke_connection(SOCKET hnew_sock, const network_address &remote_address)
{
m_connections_lock.lock();
m_connections.push_back(thread_context());
@@ -304,8 +304,7 @@ namespace net_utils
m_connections.back().m_socket = hnew_sock;
m_connections.back().powner = this;
m_connections.back().m_self_it = --m_connections.end();
- m_connections.back().m_context.m_remote_ip = ip_from;
- m_connections.back().m_context.m_remote_port = post_from;
+ m_connections.back().m_context.m_remote_address = remote_address;
m_connections.back().m_htread = threads_helper::create_thread(ConnectionHandlerProc, &m_connections.back());
return true;
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index 506949dbd..ca58d5467 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -69,7 +69,7 @@ namespace net_utils
struct i_connection_filter
{
- virtual bool is_remote_ip_allowed(uint32_t adress)=0;
+ virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address)=0;
protected:
virtual ~i_connection_filter(){}
};
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 75a9c5be9..0fbd9ed28 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -133,6 +133,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
boost::system::error_code ec;
auto remote_ep = socket_.remote_endpoint(ec);
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value());
+ CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4(), false, "IPv6 not supported here");
auto local_ep = socket_.local_endpoint(ec);
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
@@ -145,14 +146,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
// that stuff turns out to be included, even though it's from src... Taking advantage
random_uuid = crypto::rand<boost::uuids::uuid>();
- context.set_details(random_uuid, ip_, remote_ep.port(), is_income);
+ context.set_details(random_uuid, new epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
" to " << local_ep.address().to_string() << ':' << local_ep.port() <<
", total sockets objects " << m_ref_sock_count);
- if(m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip))
+ if(m_pfilter && !m_pfilter->is_remote_host_allowed(context.m_remote_address))
{
- _dbg2("[sock " << socket_.native_handle() << "] ip denied " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ", shutdowning connection");
+ _dbg2("[sock " << socket_.native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
close();
return false;
}
diff --git a/contrib/epee/include/net/abstract_tcp_server_cp.inl b/contrib/epee/include/net/abstract_tcp_server_cp.inl
index ba201e3bf..e0ef6470e 100644
--- a/contrib/epee/include/net/abstract_tcp_server_cp.inl
+++ b/contrib/epee/include/net/abstract_tcp_server_cp.inl
@@ -471,7 +471,7 @@ bool cp_server_impl<TProtocol>::run_server(int threads_count = 0)
}
//-------------------------------------------------------------
template<class TProtocol>
-bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, long ip_from, int port_from)
+bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, const network_address &address_from)
{
PROFILE_FUNC("[add_new_connection]");
@@ -487,8 +487,7 @@ bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, long ip_from
m_connections_lock.unlock();
conn.init_buffers();
conn.m_sock = new_sock;
- conn.context.m_remote_ip = ip_from;
- conn.context.m_remote_port = port_from;
+ conn.context.m_remote_address = address_from;
conn.m_completion_port = m_completion_port;
{
PROFILE_FUNC("[add_new_connection] CreateIoCompletionPort");
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 8e39b4104..429e3e1af 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -39,7 +39,7 @@
epee::net_utils::http::http_response_info& response, \
context_type& m_conn_context) \
{\
- LOG_PRINT_L2("HTTP [" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "] " << query_info.m_http_method_str << " " << query_info.m_URI); \
+ LOG_PRINT_L2("HTTP [" << m_conn_context.m_remote_address.host_str() << "] " << query_info.m_http_method_str << " " << query_info.m_URI); \
response.m_response_code = 200; \
response.m_response_comment = "Ok"; \
if(!handle_http_request_map(query_info, response, m_conn_context)) \
diff --git a/contrib/epee/include/net/levin_client_async.h b/contrib/epee/include/net/levin_client_async.h
index 2cbdb4587..4b48070d6 100644
--- a/contrib/epee/include/net/levin_client_async.h
+++ b/contrib/epee/include/net/levin_client_async.h
@@ -492,8 +492,7 @@ namespace levin
{
net_utils::connection_context_base conn_context;
- conn_context.m_remote_ip = m_ip;
- conn_context.m_remote_port = m_port;
+ conn_context.m_remote_address = m_address;
if(head.m_have_to_return_data)
{
std::string return_buff;
diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h
index fd7e28849..1884412dc 100644
--- a/contrib/epee/include/net/net_utils_base.h
+++ b/contrib/epee/include/net/net_utils_base.h
@@ -29,8 +29,11 @@
#ifndef _NET_UTILS_BASE_H_
#define _NET_UTILS_BASE_H_
+#include <typeinfo>
#include <boost/asio/io_service.hpp>
#include <boost/uuid/uuid.hpp>
+#include "serialization/keyvalue_serialization.h"
+#include "net/local_ip.h"
#include "string_tools.h"
#include "misc_log_ex.h"
@@ -46,14 +49,111 @@ namespace epee
{
namespace net_utils
{
+ struct network_address_base
+ {
+ public:
+ bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; }
+ bool operator!=(const network_address_base &other) const { return !operator==(other); }
+ bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; }
+ bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; }
+ virtual std::string str() const = 0;
+ virtual std::string host_str() const = 0;
+ virtual bool is_loopback() const = 0;
+ virtual bool is_local() const = 0;
+ virtual uint8_t get_type_id() const = 0;
+ protected:
+ // A very simple non cryptographic hash function by Fowler, Noll, Vo
+ uint64_t fnv1a(const uint8_t *data, size_t len) const {
+ uint64_t h = 0xcbf29ce484222325;
+ while (len--)
+ h = (h ^ *data++) * 0x100000001b3;
+ return h;
+ }
+ uint64_t m_host_id;
+ uint64_t m_full_id;
+ };
+ struct ipv4_network_address: public network_address_base
+ {
+ void init_ids()
+ {
+ m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip));
+ m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port));
+ }
+ public:
+ ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); }
+ uint32_t ip() const { return m_ip; }
+ uint16_t port() const { return m_port; }
+ virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); }
+ virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); }
+ virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); }
+ virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); }
+ virtual uint8_t get_type_id() const { return ID; }
+ public: // serialization
+ static const uint8_t ID = 1;
+#pragma pack(push)
+#pragma pack(1)
+ uint32_t m_ip;
+ uint16_t m_port;
+#pragma pack(pop)
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_ip)
+ KV_SERIALIZE(m_port)
+ if (!is_store)
+ const_cast<ipv4_network_address&>(this_ref).init_ids();
+ END_KV_SERIALIZE_MAP()
+ };
+ class network_address: public boost::shared_ptr<network_address_base>
+ {
+ public:
+ network_address() {}
+ network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {}
+ bool operator==(const network_address &other) const { return (*this)->operator==(*other); }
+ bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); }
+ bool operator<(const network_address &other) const { return (*this)->operator<(*other); }
+ bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); }
+ std::string str() const { return (*this) ? (*this)->str() : "<none>"; }
+ std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; }
+ bool is_loopback() const { return (*this)->is_loopback(); }
+ bool is_local() const { return (*this)->is_local(); }
+ const std::type_info &type() const { return typeid(**this); }
+ uint8_t get_type_id() const { return (*this)->get_type_id(); }
+ template<typename Type> Type &as() { if (type() != typeid(Type)) throw std::runtime_error("Bad type"); return *(Type*)get(); }
+ template<typename Type> const Type &as() const { if (type() != typeid(Type)) throw std::runtime_error("Bad type"); return *(const Type*)get(); }
+
+ BEGIN_KV_SERIALIZE_MAP()
+ uint8_t type = is_store ? this_ref.get_type_id() : 0;
+ epee::serialization::selector<is_store>::serialize(type, stg, hparent_section, "type");
+ switch (type)
+ {
+ case ipv4_network_address::ID:
+ if (!is_store)
+ const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0));
+ KV_SERIALIZE(template as<ipv4_network_address>());
+ break;
+ default: MERROR("Unsupported network address type: " << type); return false;
+ }
+ END_KV_SERIALIZE_MAP()
+ };
+ inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0)
+ {
+ uint32_t ip;
+ uint16_t port;
+ if (epee::string_tools::parse_peer_from_string(ip, port, string))
+ {
+ if (default_port && !port)
+ port = default_port;
+ address.reset(new ipv4_network_address(ip, port));
+ return true;
+ }
+ return false;
+ }
/************************************************************************/
/* */
/************************************************************************/
struct connection_context_base
{
const boost::uuids::uuid m_connection_id;
- const uint32_t m_remote_ip;
- const uint32_t m_remote_port;
+ const network_address m_remote_address;
const bool m_is_income;
const time_t m_started;
bool m_in_timedsync;
@@ -65,12 +165,11 @@ namespace net_utils
double m_current_speed_up;
connection_context_base(boost::uuids::uuid connection_id,
- long remote_ip, int remote_port, bool is_income,
+ const network_address &remote_address, bool is_income,
time_t last_recv = 0, time_t last_send = 0,
uint64_t recv_cnt = 0, uint64_t send_cnt = 0):
m_connection_id(connection_id),
- m_remote_ip(remote_ip),
- m_remote_port(remote_port),
+ m_remote_address(remote_address),
m_is_income(is_income),
m_started(time(NULL)),
m_in_timedsync(false),
@@ -83,8 +182,7 @@ namespace net_utils
{}
connection_context_base(): m_connection_id(),
- m_remote_ip(0),
- m_remote_port(0),
+ m_remote_address(new ipv4_network_address(0,0)),
m_is_income(false),
m_started(time(NULL)),
m_in_timedsync(false),
@@ -98,17 +196,17 @@ namespace net_utils
connection_context_base& operator=(const connection_context_base& a)
{
- set_details(a.m_connection_id, a.m_remote_ip, a.m_remote_port, a.m_is_income);
+ set_details(a.m_connection_id, a.m_remote_address, a.m_is_income);
return *this;
}
private:
template<class t_protocol_handler>
friend class connection;
- void set_details(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income)
+ void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income)
{
this->~connection_context_base();
- new(this) connection_context_base(connection_id, remote_ip, remote_port, is_income);
+ new(this) connection_context_base(connection_id, remote_address, is_income);
}
};
@@ -138,7 +236,7 @@ namespace net_utils
std::string print_connection_context(const connection_context_base& ctx)
{
std::stringstream ss;
- ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
+ ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
@@ -146,7 +244,7 @@ namespace net_utils
std::string print_connection_context_short(const connection_context_base& ctx)
{
std::stringstream ss;
- ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC":" OUT");
+ ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
diff --git a/contrib/epee/include/readline_buffer.h b/contrib/epee/include/readline_buffer.h
new file mode 100644
index 000000000..7d929bc4c
--- /dev/null
+++ b/contrib/epee/include/readline_buffer.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <streambuf>
+#include <sstream>
+#include <iostream>
+
+namespace rdln
+{
+ class readline_buffer : public std::stringbuf
+ {
+ public:
+ readline_buffer();
+ void start();
+ void stop();
+ int process();
+ bool is_running()
+ {
+ return m_cout_buf != NULL;
+ }
+ void get_line(std::string& line);
+ void set_prompt(const std::string& prompt);
+
+ protected:
+ virtual int sync();
+
+ private:
+ std::streambuf* m_cout_buf;
+ };
+
+ class suspend_readline
+ {
+ public:
+ suspend_readline();
+ ~suspend_readline();
+ private:
+ readline_buffer* m_buffer;
+ bool m_restart;
+ };
+}
+
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index 16e60e99a..258caa49e 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -193,7 +193,7 @@ POP_WARNINGS
//----------------------------------------------------------------------------
bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str);
//----------------------------------------------------------------------------
- inline bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres)
+ inline bool parse_peer_from_string(uint32_t& ip, uint16_t& port, const std::string& addres)
{
//parse ip and address
std::string::size_type p = addres.find(':');
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index 437851833..c61a6e684 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -26,7 +26,12 @@
# 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.
-add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp)
+if (USE_READLINE AND GNU_READLINE_FOUND)
+ add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp readline_buffer.cpp)
+else()
+ add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp)
+endif()
+
# Build and install libepee if we're building for GUI
if (BUILD_GUI_DEPS)
if(IOS)
diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp
new file mode 100644
index 000000000..68b739db9
--- /dev/null
+++ b/contrib/epee/src/readline_buffer.cpp
@@ -0,0 +1,196 @@
+#include "readline_buffer.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <sys/select.h>
+#include <unistd.h>
+#include <mutex>
+#include <condition_variable>
+
+static int process_input();
+static void install_line_handler();
+static void remove_line_handler();
+
+static std::string last_line;
+static std::string last_prompt;
+std::mutex line_mutex, sync_mutex;
+std::condition_variable have_line;
+
+namespace
+{
+ rdln::readline_buffer* current = NULL;
+}
+
+rdln::suspend_readline::suspend_readline()
+{
+ m_buffer = current;
+ if(!m_buffer)
+ return;
+ m_restart = m_buffer->is_running();
+ if(m_restart)
+ m_buffer->stop();
+}
+
+rdln::suspend_readline::~suspend_readline()
+{
+ if(!m_buffer)
+ return;
+ if(m_restart)
+ m_buffer->start();
+}
+
+rdln::readline_buffer::readline_buffer()
+: std::stringbuf()
+{
+ current = this;
+}
+
+void rdln::readline_buffer::start()
+{
+ if(m_cout_buf != NULL)
+ return;
+ m_cout_buf = std::cout.rdbuf();
+ std::cout.rdbuf(this);
+ install_line_handler();
+}
+
+void rdln::readline_buffer::stop()
+{
+ if(m_cout_buf == NULL)
+ return;
+ std::cout.rdbuf(m_cout_buf);
+ m_cout_buf = NULL;
+ remove_line_handler();
+}
+
+void rdln::readline_buffer::get_line(std::string& line)
+{
+ std::unique_lock<std::mutex> lock(line_mutex);
+ have_line.wait(lock);
+ line = last_line;
+}
+
+void rdln::readline_buffer::set_prompt(const std::string& prompt)
+{
+ last_prompt = prompt;
+ if(m_cout_buf == NULL)
+ return;
+ rl_set_prompt(last_prompt.c_str());
+ rl_redisplay();
+}
+
+int rdln::readline_buffer::process()
+{
+ if(m_cout_buf == NULL)
+ return 0;
+ return process_input();
+}
+
+int rdln::readline_buffer::sync()
+{
+ std::lock_guard<std::mutex> lock(sync_mutex);
+ char* saved_line;
+ int saved_point;
+
+ saved_point = rl_point;
+ saved_line = rl_copy_text(0, rl_end);
+
+ rl_set_prompt("");
+ rl_replace_line("", 0);
+ rl_redisplay();
+
+ do
+ {
+ char x = this->sgetc();
+ m_cout_buf->sputc(x);
+ }
+ while ( this->snextc() != EOF );
+
+ rl_set_prompt(last_prompt.c_str());
+ rl_replace_line(saved_line, 0);
+ rl_point = saved_point;
+ rl_redisplay();
+ free(saved_line);
+
+ return 0;
+}
+
+static fd_set fds;
+
+static int process_input()
+{
+ int count;
+ struct timeval t;
+
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ count = select(FD_SETSIZE, &fds, NULL, NULL, &t);
+ if (count < 1)
+ {
+ return count;
+ }
+ rl_callback_read_char();
+ return count;
+}
+
+static void handle_line(char* line)
+{
+ if (line != NULL)
+ {
+ std::lock_guard<std::mutex> lock(sync_mutex);
+ rl_set_prompt(last_prompt.c_str());
+ rl_already_prompted = 1;
+ return;
+ }
+ rl_set_prompt("");
+ rl_replace_line("", 0);
+ rl_redisplay();
+ rl_set_prompt(last_prompt.c_str());
+}
+
+static int handle_enter(int x, int y)
+{
+ std::lock_guard<std::mutex> lock(sync_mutex);
+ char* line = NULL;
+
+ line = rl_copy_text(0, rl_end);
+ rl_set_prompt("");
+ rl_replace_line("", 1);
+ rl_redisplay();
+
+ if (strcmp(line, "") != 0)
+ {
+ last_line = line;
+ add_history(line);
+ have_line.notify_one();
+ }
+ free(line);
+
+ rl_set_prompt(last_prompt.c_str());
+ rl_redisplay();
+
+ rl_done = 1;
+ return 0;
+}
+
+static int startup_hook()
+{
+ rl_bind_key(RETURN, handle_enter);
+ rl_bind_key(NEWLINE, handle_enter);
+ return 0;
+}
+
+static void install_line_handler()
+{
+ rl_startup_hook = startup_hook;
+ rl_callback_handler_install("", handle_line);
+}
+
+static void remove_line_handler()
+{
+ rl_unbind_key(RETURN);
+ rl_callback_handler_remove();
+}
+
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index b0a3d84e1..27e63801d 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1317,6 +1317,16 @@ public:
* @brief get a txpool transaction's blob
*
* @param txid the transaction id of the transation to lookup
+ * @param bd the blob to return
+ *
+ * @return true if the txid was in the txpool, false otherwise
+ */
+ virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const = 0;
+
+ /**
+ * @brief get a txpool transaction's blob
+ *
+ * @param txid the transaction id of the transation to lookup
*
* @return the blob for that transaction
*/
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index d7947c8d0..6bb96d1db 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -1576,7 +1576,7 @@ txpool_tx_meta_t BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid) co
return meta;
}
-cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const
+bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -1587,12 +1587,21 @@ cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid
MDB_val k = {sizeof(txid), (void *)&txid};
MDB_val v;
auto result = mdb_cursor_get(m_cur_txpool_blob, &k, &v, MDB_SET);
+ if (result == MDB_NOTFOUND)
+ return false;
if (result != 0)
- throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx blob: ", result).c_str()));
- blobdata bd;
bd.assign(reinterpret_cast<const char*>(v.mv_data), v.mv_size);
TXN_POSTFIX_RDONLY();
+ return true;
+}
+
+cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const
+{
+ cryptonote::blobdata bd;
+ if (!get_txpool_tx_blob(txid, bd))
+ throw1(DB_ERROR("Tx not found in txpool: "));
return bd;
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 540fababb..14e5d34e2 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -245,6 +245,7 @@ public:
virtual bool txpool_has_tx(const crypto::hash &txid) const;
virtual void remove_txpool_tx(const crypto::hash& txid);
virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const;
+ virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false) const;
diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp
index f71b3e576..8c2796bbe 100644
--- a/src/common/command_line.cpp
+++ b/src/common/command_line.cpp
@@ -37,6 +37,10 @@
#include "cryptonote_config.h"
#include "string_tools.h"
+#ifdef HAVE_READLINE
+ #include "readline_buffer.h"
+#endif
+
namespace command_line
{
namespace
@@ -49,6 +53,9 @@ namespace command_line
std::string input_line(const std::string& prompt)
{
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
std::cout << prompt;
std::string buf;
diff --git a/src/common/password.cpp b/src/common/password.cpp
index bdc9c69c0..5c04023f4 100644
--- a/src/common/password.cpp
+++ b/src/common/password.cpp
@@ -42,6 +42,10 @@
#include <unistd.h>
#endif
+#ifdef HAVE_READLINE
+ #include "readline_buffer.h"
+#endif
+
namespace
{
#if defined(_WIN32)
@@ -238,6 +242,9 @@ namespace tools
boost::optional<password_container> password_container::prompt(const bool verify, const char *message)
{
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
password_container pass1{};
password_container pass2{};
if (is_cin_tty() ? read_from_tty(verify, message, pass1.m_password, pass2.m_password) : read_from_file(pass1.m_password))
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index 98da466cc..1c7adff3b 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -81,12 +81,16 @@ namespace crypto {
}
/* generate a random 32-byte (256-bit) integer and copy it to res */
- static inline void random_scalar(ec_scalar &res) {
+ static inline void random_scalar_not_thread_safe(ec_scalar &res) {
unsigned char tmp[64];
generate_random_bytes_not_thread_safe(64, tmp);
sc_reduce(tmp);
memcpy(&res, tmp, 32);
}
+ static inline void random_scalar(ec_scalar &res) {
+ boost::lock_guard<boost::mutex> lock(random_lock);
+ random_scalar_not_thread_safe(res);
+ }
static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
cn_fast_hash(data, length, reinterpret_cast<hash &>(res));
@@ -99,7 +103,6 @@ namespace crypto {
*
*/
secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
- boost::lock_guard<boost::mutex> lock(random_lock);
ge_p3 point;
secret_key rng;
@@ -197,8 +200,14 @@ namespace crypto {
ec_point comm;
};
+ struct s_comm_2 {
+ hash msg;
+ ec_point D;
+ ec_point X;
+ ec_point Y;
+ };
+
void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
- boost::lock_guard<boost::mutex> lock(random_lock);
ge_p3 tmp3;
ec_scalar k;
s_comm buf;
@@ -242,6 +251,124 @@ namespace crypto {
return sc_isnonzero(&c) == 0;
}
+ void crypto_ops::generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const secret_key &r, signature &sig) {
+ // sanity check
+ ge_p3 R_p3;
+ ge_p3 A_p3;
+ ge_p3 D_p3;
+ if (ge_frombytes_vartime(&R_p3, &R) != 0) throw std::runtime_error("tx pubkey is invalid");
+ if (ge_frombytes_vartime(&A_p3, &A) != 0) throw std::runtime_error("recipient view pubkey is invalid");
+ if (ge_frombytes_vartime(&D_p3, &D) != 0) throw std::runtime_error("key derivation is invalid");
+#if !defined(NDEBUG)
+ {
+ assert(sc_check(&r) == 0);
+ // check R == r*G
+ ge_p3 dbg_R_p3;
+ ge_scalarmult_base(&dbg_R_p3, &r);
+ public_key dbg_R;
+ ge_p3_tobytes(&dbg_R, &dbg_R_p3);
+ assert(R == dbg_R);
+ // check D == r*A
+ ge_p2 dbg_D_p2;
+ ge_scalarmult(&dbg_D_p2, &r, &A_p3);
+ public_key dbg_D;
+ ge_tobytes(&dbg_D, &dbg_D_p2);
+ assert(D == dbg_D);
+ }
+#endif
+
+ // pick random k
+ ec_scalar k;
+ random_scalar(k);
+
+ // compute X = k*G
+ ge_p3 X_p3;
+ ge_scalarmult_base(&X_p3, &k);
+
+ // compute Y = k*A
+ ge_p2 Y_p2;
+ ge_scalarmult(&Y_p2, &k, &A_p3);
+
+ // sig.c = Hs(Msg || D || X || Y)
+ s_comm_2 buf;
+ buf.msg = prefix_hash;
+ buf.D = D;
+ ge_p3_tobytes(&buf.X, &X_p3);
+ ge_tobytes(&buf.Y, &Y_p2);
+ hash_to_scalar(&buf, sizeof(s_comm_2), sig.c);
+
+ // sig.r = k - sig.c*r
+ sc_mulsub(&sig.r, &sig.c, &r, &k);
+ }
+
+ bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const signature &sig) {
+ // sanity check
+ ge_p3 R_p3;
+ ge_p3 A_p3;
+ ge_p3 D_p3;
+ if (ge_frombytes_vartime(&R_p3, &R) != 0) return false;
+ if (ge_frombytes_vartime(&A_p3, &A) != 0) return false;
+ if (ge_frombytes_vartime(&D_p3, &D) != 0) return false;
+ if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) return false;
+
+ // compute sig.c*R
+ ge_p2 cR_p2;
+ ge_scalarmult(&cR_p2, &sig.c, &R_p3);
+
+ // compute sig.r*G
+ ge_p3 rG_p3;
+ ge_scalarmult_base(&rG_p3, &sig.r);
+
+ // compute sig.c*D
+ ge_p2 cD_p2;
+ ge_scalarmult(&cD_p2, &sig.c, &D_p3);
+
+ // compute sig.r*A
+ ge_p2 rA_p2;
+ ge_scalarmult(&rA_p2, &sig.r, &A_p3);
+
+ // compute X = sig.c*R + sig.r*G
+ public_key cR;
+ ge_tobytes(&cR, &cR_p2);
+ ge_p3 cR_p3;
+ if (ge_frombytes_vartime(&cR_p3, &cR) != 0) return false;
+ ge_cached rG_cached;
+ ge_p3_to_cached(&rG_cached, &rG_p3);
+ ge_p1p1 X_p1p1;
+ ge_add(&X_p1p1, &cR_p3, &rG_cached);
+ ge_p2 X_p2;
+ ge_p1p1_to_p2(&X_p2, &X_p1p1);
+
+ // compute Y = sig.c*D + sig.r*A
+ public_key cD;
+ public_key rA;
+ ge_tobytes(&cD, &cD_p2);
+ ge_tobytes(&rA, &rA_p2);
+ ge_p3 cD_p3;
+ ge_p3 rA_p3;
+ if (ge_frombytes_vartime(&cD_p3, &cD) != 0) return false;
+ if (ge_frombytes_vartime(&rA_p3, &rA) != 0) return false;
+ ge_cached rA_cached;
+ ge_p3_to_cached(&rA_cached, &rA_p3);
+ ge_p1p1 Y_p1p1;
+ ge_add(&Y_p1p1, &cD_p3, &rA_cached);
+ ge_p2 Y_p2;
+ ge_p1p1_to_p2(&Y_p2, &Y_p1p1);
+
+ // compute c2 = Hs(Msg || D || X || Y)
+ s_comm_2 buf;
+ buf.msg = prefix_hash;
+ buf.D = D;
+ ge_tobytes(&buf.X, &X_p2);
+ ge_tobytes(&buf.Y, &Y_p2);
+ ec_scalar c2;
+ hash_to_scalar(&buf, sizeof(s_comm_2), c2);
+
+ // test if c2 == sig.c
+ sc_sub(&c2, &c2, &sig.c);
+ return sc_isnonzero(&c2) == 0;
+ }
+
static void hash_to_ec(const public_key &key, ge_p3 &res) {
hash h;
ge_p2 point;
@@ -280,7 +407,6 @@ POP_WARNINGS
const public_key *const *pubs, size_t pubs_count,
const secret_key &sec, size_t sec_index,
signature *sig) {
- boost::lock_guard<boost::mutex> lock(random_lock);
size_t i;
ge_p3 image_unp;
ge_dsmp image_pre;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 3b8c7996b..e99b6651f 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -123,6 +123,10 @@ namespace crypto {
friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
static bool check_signature(const hash &, const public_key &, const signature &);
friend bool check_signature(const hash &, const public_key &, const signature &);
+ static void generate_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const secret_key &, signature &);
+ friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const secret_key &, signature &);
+ static bool check_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const signature &);
+ friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const public_key &, const signature &);
static void generate_key_image(const public_key &, const secret_key &, key_image &);
friend void generate_key_image(const public_key &, const secret_key &, key_image &);
static void generate_ring_signature(const hash &, const key_image &,
@@ -200,6 +204,16 @@ namespace crypto {
return crypto_ops::check_signature(prefix_hash, pub, sig);
}
+ /* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key
+ * derivation D, the signature proves the knowledge of the tx secret key r such that R=r*G and D=r*A
+ */
+ inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const secret_key &r, signature &sig) {
+ crypto_ops::generate_tx_proof(prefix_hash, R, A, D, r, sig);
+ }
+ inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const public_key &D, const signature &sig) {
+ return crypto_ops::check_tx_proof(prefix_hash, R, A, D, sig);
+ }
+
/* To send money to a key:
* * The sender generates an ephemeral key and includes it in transaction output.
* * To spend the money, the receiver generates a key image from it.
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index 6afa28934..b92b6e6c3 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -979,34 +979,31 @@ STATIC void cn_mul128(const uint64_t *a, const uint64_t *b, uint64_t *r)
r[1] = lo;
}
#else /* ARM32 */
-/* Can work as inline, but actually runs slower. Keep it separate */
#define mul(a, b, c) cn_mul128((const uint32_t *)a, (const uint32_t *)b, (uint32_t *)c)
-void cn_mul128(const uint32_t *aa, const uint32_t *bb, uint32_t *r)
+STATIC void cn_mul128(const uint32_t *aa, const uint32_t *bb, uint32_t *r)
{
- uint32_t t0, t1;
+ uint32_t t0, t1, t2=0, t3=0;
__asm__ __volatile__(
"umull %[t0], %[t1], %[a], %[b]\n\t"
- "str %[t0], [%[r], #8]\n\t"
+ "str %[t0], %[ll]\n\t"
// accumulating with 0 can never overflow/carry
- "mov %[t0], #0\n\t"
+ "eor %[t0], %[t0]\n\t"
"umlal %[t1], %[t0], %[a], %[B]\n\t"
- "mov %[a], #0\n\t"
- "umlal %[t1], %[a], %[A], %[b]\n\t"
- "str %[t1], [%[r], #12]\n\t"
+ "umlal %[t1], %[t2], %[A], %[b]\n\t"
+ "str %[t1], %[lh]\n\t"
- "mov %[b], #0\n\t"
- "umlal %[t0], %[b], %[A], %[B]\n\t"
+ "umlal %[t0], %[t3], %[A], %[B]\n\t"
// final add may have a carry
- "adds %[t0], %[t0], %[a]\n\t"
- "adc %[t1], %[b], #0\n\t"
+ "adds %[t0], %[t0], %[t2]\n\t"
+ "adc %[t1], %[t3], #0\n\t"
- "str %[t0], [%[r]]\n\t"
- "str %[t1], [%[r], #4]\n\t"
- : [t0]"=&r"(t0), [t1]"=&r"(t1), "=m"(r[0]), "=m"(r[1]), "=m"(r[2]), "=m"(r[3])
- : [A]"r"(aa[1]), [a]"r"(aa[0]), [B]"r"(bb[1]), [b]"r"(bb[0]), [r]"r"(r)
+ "str %[t0], %[hl]\n\t"
+ "str %[t1], %[hh]\n\t"
+ : [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"+r"(t2), [t3]"+r"(t3), [hl]"=m"(r[0]), [hh]"=m"(r[1]), [ll]"=m"(r[2]), [lh]"=m"(r[3])
+ : [A]"r"(aa[1]), [a]"r"(aa[0]), [B]"r"(bb[1]), [b]"r"(bb[0])
: "cc");
}
#endif /* !aarch64 */
diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt
index ec7aa251f..1503b277e 100644
--- a/src/cryptonote_basic/CMakeLists.txt
+++ b/src/cryptonote_basic/CMakeLists.txt
@@ -26,6 +26,12 @@
# 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.
+if(APPLE)
+ find_library(IOKIT_LIBRARY IOKit)
+ mark_as_advanced(IOKIT_LIBRARY)
+ list(APPEND EXTRA_LIBRARIES ${IOKIT_LIBRARY})
+endif()
+
set(cryptonote_basic_sources
account.cpp
checkpoints.cpp
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index eeb7b6094..6928a0ded 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -43,6 +43,16 @@
#include "storages/portable_storage_template_helper.h"
#include "boost/logic/tribool.hpp"
+#ifdef __APPLE__
+ #include <sys/times.h>
+ #include <IOKit/IOKitLib.h>
+ #include <IOKit/ps/IOPSKeys.h>
+ #include <IOKit/ps/IOPowerSources.h>
+ #include <mach/mach_host.h>
+ #include <AvailabilityMacros.h>
+ #include <TargetConditionals.h>
+#endif
+
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "miner"
@@ -757,6 +767,23 @@ namespace cryptonote
return true;
+ #elif defined(__APPLE__)
+
+ mach_msg_type_number_t count;
+ kern_return_t status;
+ host_cpu_load_info_data_t stats;
+ count = HOST_CPU_LOAD_INFO_COUNT;
+ status = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&stats, &count);
+ if(status != KERN_SUCCESS)
+ {
+ return false;
+ }
+
+ idle_time = stats.cpu_ticks[CPU_STATE_IDLE];
+ total_time = idle_time + stats.cpu_ticks[CPU_STATE_USER] + stats.cpu_ticks[CPU_STATE_SYSTEM];
+
+ return true;
+
#endif
return false; // unsupported systemm..
@@ -779,7 +806,7 @@ namespace cryptonote
return true;
}
- #elif defined(__linux__) && defined(_SC_CLK_TCK)
+ #elif (defined(__linux__) && defined(_SC_CLK_TCK)) || defined(__APPLE__)
struct tms tms;
if ( times(&tms) != (clock_t)-1 )
@@ -808,6 +835,15 @@ namespace cryptonote
return boost::logic::tribool(power_status.ACLineStatus != 1);
}
+ #elif defined(__APPLE__)
+
+ #if TARGET_OS_MAC && (!defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)
+ return boost::logic::tribool(IOPSGetTimeRemainingEstimate() != kIOPSTimeRemainingUnlimited);
+ #else
+ // iOS or OSX <10.7
+ return boost::logic::tribool(boost::logic::indeterminate);
+ #endif
+
#elif defined(__linux__)
// i've only tested on UBUNTU, these paths might be different on other systems
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 6f2977c5b..745608b9f 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -4005,6 +4005,11 @@ txpool_tx_meta_t Blockchain::get_txpool_tx_meta(const crypto::hash& txid) const
return m_db->get_txpool_tx_meta(txid);
}
+bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
+{
+ return m_db->get_txpool_tx_blob(txid, bd);
+}
+
cryptonote::blobdata Blockchain::get_txpool_tx_blob(const crypto::hash& txid) const
{
return m_db->get_txpool_tx_blob(txid);
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 52172012c..56373adf9 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -862,6 +862,7 @@ namespace cryptonote
void remove_txpool_tx(const crypto::hash &txid);
uint64_t get_txpool_tx_count() const;
txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const;
+ bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false) const;
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 515918cfa..ffb5b478b 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -556,8 +556,9 @@ namespace cryptonote
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
const uint64_t now = time(NULL);
+ std::map<uint64_t, txpool_histo> agebytes;
stats.txs_total = m_blockchain.get_txpool_tx_count();
- m_blockchain.for_all_txpool_txes([&stats, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
+ m_blockchain.for_all_txpool_txes([&stats, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
stats.bytes_total += meta.blob_size;
if (!stats.bytes_min || meta.blob_size < stats.bytes_min)
stats.bytes_min = meta.blob_size;
@@ -572,8 +573,53 @@ namespace cryptonote
stats.num_10m++;
if (meta.last_failed_height)
stats.num_failing++;
+ uint64_t age = now - meta.receive_time;
+ agebytes[age].txs++;
+ agebytes[age].bytes += meta.blob_size;
return true;
});
+ if (stats.txs_total > 1)
+ {
+ /* looking for 98th percentile */
+ size_t end = stats.txs_total * 0.02;
+ uint64_t delta, factor;
+ std::map<uint64_t, txpool_histo>::iterator it, i2;
+ if (end)
+ {
+ /* If enough txs, spread the first 98% of results across
+ * the first 9 bins, drop final 2% in last bin.
+ */
+ it=agebytes.end();
+ for (size_t n=0; n <= end; n++, it--);
+ stats.histo_98pc = it->first;
+ factor = 9;
+ delta = it->first;
+ stats.histo.resize(10);
+ } else
+ {
+ /* If not enough txs, don't reserve the last slot;
+ * spread evenly across all 10 bins.
+ */
+ stats.histo_98pc = 0;
+ it = agebytes.end();
+ factor = stats.txs_total > 9 ? 10 : stats.txs_total;
+ delta = now - stats.oldest;
+ stats.histo.resize(factor);
+ }
+ if (!delta)
+ delta = 1;
+ for (i2 = agebytes.begin(); i2 != it; i2++)
+ {
+ size_t i = (i2->first * factor - 1) / delta;
+ stats.histo[i].txs += i2->second.txs;
+ stats.histo[i].bytes += i2->second.bytes;
+ }
+ for (; i2 != agebytes.end(); i2++)
+ {
+ stats.histo[factor].txs += i2->second.txs;
+ stats.histo[factor].bytes += i2->second.bytes;
+ }
+ }
}
//------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
@@ -627,8 +673,7 @@ namespace cryptonote
CRITICAL_REGION_LOCAL1(m_blockchain);
try
{
- txblob = m_blockchain.get_txpool_tx_blob(id);
- return true;
+ return m_blockchain.get_txpool_tx_blob(id, txblob);
}
catch (const std::exception &e)
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index fd5b980b8..6f6c1a803 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -49,6 +49,8 @@ namespace cryptonote
bool localhost;
bool local_ip;
+ std::string address;
+ std::string host;
std::string ip;
std::string port;
@@ -76,6 +78,8 @@ namespace cryptonote
KV_SERIALIZE(incoming)
KV_SERIALIZE(localhost)
KV_SERIALIZE(local_ip)
+ KV_SERIALIZE(address)
+ KV_SERIALIZE(host)
KV_SERIALIZE(ip)
KV_SERIALIZE(port)
KV_SERIALIZE(peer_id)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 8b41ce514..0b99aa7bd 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -134,17 +134,12 @@ namespace cryptonote
<< std::setw(13) << "Up(now)"
<< ENDL;
- uint32_t ip;
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
{
- bool local_ip = false;
- ip = ntohl(cntxt.m_remote_ip);
- // TODO: local ip in calss A, B
- if (ip > 3232235520 && ip < 3232301055) // 192.168.x.x
- local_ip = true;
+ bool local_ip = cntxt.m_remote_address.is_local();
auto connection_time = time(NULL) - cntxt.m_started;
ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
- epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
+ cntxt.m_remote_address.str()
<< std::setw(20) << std::hex << peer_id
<< std::setw(20) << std::hex << support_flags
<< std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
@@ -155,7 +150,7 @@ namespace cryptonote
<< std::setw(10) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_send_cnt / connection_time / 1024)
<< std::setw(13) << std::fixed << cntxt.m_current_speed_up / 1024
<< (local_ip ? "[LAN]" : "")
- << std::left << (ip == LOCALHOST_INT ? "[LOCALHOST]" : "") // 127.0.0.1
+ << std::left << (cntxt.m_remote_address.is_loopback() ? "[LOCALHOST]" : "") // 127.0.0.1
<< ENDL;
if (connection_time > 1)
@@ -193,8 +188,15 @@ namespace cryptonote
cnx.incoming = cntxt.m_is_income ? true : false;
- cnx.ip = epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip);
- cnx.port = std::to_string(cntxt.m_remote_port);
+ cnx.address = cntxt.m_remote_address.str();
+ cnx.host = cntxt.m_remote_address.host_str();
+ cnx.ip = "";
+ cnx.port = "";
+ if (cntxt.m_remote_address.type() == typeid(epee::net_utils::ipv4_network_address))
+ {
+ cnx.ip = cnx.host;
+ cnx.port = std::to_string(cntxt.m_remote_address.as<epee::net_utils::ipv4_network_address>().port());
+ }
std::stringstream peer_id_str;
peer_id_str << std::hex << peer_id;
@@ -212,25 +214,8 @@ namespace cryptonote
cnx.live_time = timestamp - cntxt.m_started;
- uint32_t ip;
- ip = ntohl(cntxt.m_remote_ip);
- if (ip == LOCALHOST_INT)
- {
- cnx.localhost = true;
- }
- else
- {
- cnx.localhost = false;
- }
-
- if (ip > 3232235520 && ip < 3232301055) // 192.168.x.x
- {
- cnx.local_ip = true;
- }
- else
- {
- cnx.local_ip = false;
- }
+ cnx.localhost = cntxt.m_remote_address.is_loopback();
+ cnx.local_ip = cntxt.m_remote_address.is_local();
auto connection_time = time(NULL) - cntxt.m_started;
if (connection_time == 0)
@@ -662,9 +647,6 @@ namespace cryptonote
return 1;
}
- for (auto txidx: arg.missing_tx_indices)
- MDEBUG(" tx " << b.tx_hashes[txidx]);
-
std::vector<crypto::hash> txids;
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
fluffy_response.b.block = t_serializable_object_to_blob(b);
@@ -674,6 +656,7 @@ namespace cryptonote
{
if(tx_idx < b.tx_hashes.size())
{
+ MDEBUG(" tx " << b.tx_hashes[tx_idx]);
txids.push_back(b.tx_hashes[tx_idx]);
}
else
@@ -990,7 +973,7 @@ namespace cryptonote
{
LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
m_p2p->drop_connection(context);
- m_p2p->add_ip_fail(context.m_remote_ip);
+ m_p2p->add_host_fail(context.m_remote_address);
m_core.cleanup_handle_incoming_blocks();
return 1;
}
@@ -998,7 +981,7 @@ namespace cryptonote
{
LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
m_p2p->drop_connection(context);
- m_p2p->add_ip_fail(context.m_remote_ip);
+ m_p2p->add_host_fail(context.m_remote_address);
m_core.cleanup_handle_incoming_blocks();
return 1;
}
@@ -1150,7 +1133,7 @@ skip:
{
LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
m_p2p->drop_connection(context);
- m_p2p->add_ip_fail(context.m_remote_ip);
+ m_p2p->add_host_fail(context.m_remote_address);
return 1;
}
@@ -1159,7 +1142,7 @@ skip:
LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: "
<< epee::string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection");
m_p2p->drop_connection(context);
- m_p2p->add_ip_fail(context.m_remote_ip);
+ m_p2p->add_host_fail(context.m_remote_address);
return 1;
}
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index d5bde7f09..1c9cd714d 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -92,6 +92,19 @@ namespace {
return s + " " + (t > now ? "in the future" : "ago");
}
+ std::string get_time_hms(time_t t)
+ {
+ unsigned int hours, minutes, seconds;
+ char buffer[24];
+ hours = t / 3600;
+ t %= 3600;
+ minutes = t / 60;
+ t %= 60;
+ seconds = t;
+ snprintf(buffer, sizeof(buffer), "%02u:%02u:%02u", hours, minutes, seconds);
+ return std::string(buffer);
+ }
+
std::string make_error(const std::string &base, const std::string &status)
{
if (status == CORE_RPC_STATUS_OK)
@@ -939,7 +952,35 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
tools::msg_writer() << n_transactions << " tx(es), " << res.pool_stats.bytes_total << " bytes total (min " << res.pool_stats.bytes_min << ", max " << res.pool_stats.bytes_max << ", avg " << avg_bytes << ")" << std::endl
<< "fees " << cryptonote::print_money(res.pool_stats.fee_total) << " (avg " << cryptonote::print_money(n_transactions ? res.pool_stats.fee_total / n_transactions : 0) << " per tx" << ", " << cryptonote::print_money(res.pool_stats.bytes_total ? res.pool_stats.fee_total / res.pool_stats.bytes_total : 0) << " per byte )" << std::endl
- << res.pool_stats.num_not_relayed << " not relayed, " << res.pool_stats.num_failing << " failing, " << res.pool_stats.num_10m << " older than 10 minutes (oldest " << (res.pool_stats.oldest == 0 ? "-" : get_human_time_ago(res.pool_stats.oldest, now)) << ")" << std::endl;
+ << res.pool_stats.num_not_relayed << " not relayed, " << res.pool_stats.num_failing << " failing, " << res.pool_stats.num_10m << " older than 10 minutes (oldest " << (res.pool_stats.oldest == 0 ? "-" : get_human_time_ago(res.pool_stats.oldest, now)) << ")";
+
+ if (n_transactions > 1 && res.pool_stats.histo.size())
+ {
+ std::vector<uint64_t> times;
+ uint64_t numer;
+ size_t i, n = res.pool_stats.histo.size(), denom;
+ times.resize(n);
+ if (res.pool_stats.histo_98pc)
+ {
+ numer = res.pool_stats.histo_98pc;
+ denom = n-1;
+ for (i=0; i<denom; i++)
+ times[i] = i * numer / denom;
+ times[i] = res.pool_stats.oldest;
+ } else
+ {
+ numer = now - res.pool_stats.oldest;
+ denom = n;
+ for (i=0; i<denom; i++)
+ times[i] = i * numer / denom;
+ }
+ tools::msg_writer() << " Age Txes Bytes";
+ for (i=0; i<n; i++)
+ {
+ tools::msg_writer() << get_time_hms(times[i]) << setw(8) << res.pool_stats.histo[i].txs << setw(12) << res.pool_stats.histo[i].bytes;
+ }
+ }
+ tools::msg_writer();
return true;
}
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 13cd3f5b0..8798a52e0 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -123,9 +123,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() { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); return m_blocked_ips; }
+ virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME);
+ virtual bool unblock_host(const epee::net_utils::network_address &address);
+ virtual std::map<std::string, time_t> get_blocked_hosts() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_hosts; }
private:
const std::vector<std::string> m_seed_nodes_list =
{ "seeds.moneroseeds.se"
@@ -186,11 +186,11 @@ 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, uint32_t)> f);
- virtual bool add_ip_fail(uint32_t address);
+ virtual bool add_host_fail(const epee::net_utils::network_address &address);
//----------------- i_connection_filter --------------------------------------------------------
- virtual bool is_remote_ip_allowed(uint32_t adress);
+ virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address);
//-----------------------------------------------------------------------------------------------
- bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr);
+ bool parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port = 0);
bool handle_command_line(
const boost::program_options::variables_map& vm
);
@@ -209,18 +209,18 @@ namespace nodetool
bool make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist);
bool make_new_connection_from_peerlist(bool use_white_list);
- bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, PeerType peer_type = white, uint64_t first_seen_stamp = 0);
+ bool try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, PeerType peer_type = white, uint64_t first_seen_stamp = 0);
size_t get_random_index_with_fixed_probability(size_t max_index);
bool is_peer_used(const peerlist_entry& peer);
bool is_peer_used(const anchor_peerlist_entry& peer);
- bool is_addr_connected(const net_address& peer);
+ bool is_addr_connected(const epee::net_utils::network_address& peer);
template<class t_callback>
bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb);
bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f);
bool make_expected_connections_count(PeerType peer_type, size_t expected_connections);
- void cache_connect_fail_info(const net_address& addr);
- bool is_addr_recently_failed(const net_address& addr);
- bool is_priority_node(const net_address& na);
+ void cache_connect_fail_info(const epee::net_utils::network_address& addr);
+ bool is_addr_recently_failed(const epee::net_utils::network_address& addr);
+ bool is_priority_node(const epee::net_utils::network_address& na);
std::set<std::string> get_seed_nodes(bool testnet) const;
template <class Container>
@@ -236,9 +236,9 @@ namespace nodetool
bool set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit);
bool set_rate_limit(const boost::program_options::variables_map& vm, int64_t limit);
- bool has_too_many_connections(const uint32_t ip);
+ bool has_too_many_connections(const epee::net_utils::network_address &address);
- bool check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp);
+ bool check_connection_and_handshake_with_peer(const epee::net_utils::network_address& na, uint64_t last_seen_stamp);
bool gray_peerlist_housekeeping();
void kill() { ///< will be called e.g. from deinit()
@@ -308,23 +308,23 @@ namespace nodetool
#ifdef ALLOW_DEBUG_COMMANDS
uint64_t m_last_stat_request_time;
#endif
- std::list<net_address> m_priority_peers;
- std::vector<net_address> m_exclusive_peers;
- std::vector<net_address> m_seed_nodes;
+ std::list<epee::net_utils::network_address> m_priority_peers;
+ std::vector<epee::net_utils::network_address> m_exclusive_peers;
+ std::vector<epee::net_utils::network_address> m_seed_nodes;
std::list<nodetool::peerlist_entry> m_command_line_peers;
uint64_t m_peer_livetime;
//keep connections to initiate some interactions
net_server m_net_server;
boost::uuids::uuid m_network_id;
- std::map<net_address, time_t> m_conn_fails_cache;
+ std::map<epee::net_utils::network_address, time_t> m_conn_fails_cache;
epee::critical_section m_conn_fails_cache_lock;
- epee::critical_section m_blocked_ips_lock;
- std::map<uint32_t, time_t> m_blocked_ips;
+ epee::critical_section m_blocked_hosts_lock;
+ std::map<std::string, time_t> m_blocked_hosts;
- epee::critical_section m_ip_fails_score_lock;
- std::map<uint32_t, uint64_t> m_ip_fails_score;
+ epee::critical_section m_host_fails_score_lock;
+ std::map<std::string, uint64_t> m_host_fails_score;
bool m_testnet;
};
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 0d0d86e14..c250d5185 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -200,16 +200,16 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::is_remote_ip_allowed(uint32_t addr)
+ bool node_server<t_payload_net_handler>::is_remote_host_allowed(const epee::net_utils::network_address &address)
{
- CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
- auto it = m_blocked_ips.find(addr);
- if(it == m_blocked_ips.end())
+ CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
+ auto it = m_blocked_hosts.find(address.host_str());
+ if(it == m_blocked_hosts.end())
return true;
if(time(nullptr) >= it->second)
{
- m_blocked_ips.erase(it);
- MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ m_blocked_hosts.erase(it);
+ MCLOG_CYAN(el::Level::Info, "global", "Host " << address.host_str() << " unblocked.");
return true;
}
return false;
@@ -229,16 +229,16 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::block_ip(uint32_t addr, time_t seconds)
+ bool node_server<t_payload_net_handler>::block_host(const epee::net_utils::network_address &addr, time_t seconds)
{
- CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
- m_blocked_ips[addr] = time(nullptr) + seconds;
+ CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
+ m_blocked_hosts[addr.host_str()] = time(nullptr) + seconds;
// drop any connection to that IP
std::list<boost::uuids::uuid> conns;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if (cntxt.m_remote_ip == addr)
+ if (cntxt.m_remote_address.is_same_host(addr))
{
conns.push_back(cntxt.m_connection_id);
}
@@ -247,42 +247,42 @@ namespace nodetool
for (const auto &c: conns)
m_net_server.get_config_object().close(c);
- MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked.");
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::unblock_ip(uint32_t addr)
+ bool node_server<t_payload_net_handler>::unblock_host(const epee::net_utils::network_address &address)
{
- CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
- auto i = m_blocked_ips.find(addr);
- if (i == m_blocked_ips.end())
+ CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
+ auto i = m_blocked_hosts.find(address.host_str());
+ if (i == m_blocked_hosts.end())
return false;
- m_blocked_ips.erase(i);
- MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ m_blocked_hosts.erase(i);
+ MCLOG_CYAN(el::Level::Info, "global", "Host " << address.host_str() << " unblocked.");
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::add_ip_fail(uint32_t address)
+ bool node_server<t_payload_net_handler>::add_host_fail(const epee::net_utils::network_address &address)
{
- CRITICAL_REGION_LOCAL(m_ip_fails_score_lock);
- uint64_t fails = ++m_ip_fails_score[address];
- MDEBUG("IP " << epee::string_tools::get_ip_string_from_int32(address) << " fail score=" << fails);
+ CRITICAL_REGION_LOCAL(m_host_fails_score_lock);
+ uint64_t fails = ++m_host_fails_score[address.host_str()];
+ MDEBUG("Host " << address.host_str() << " fail score=" << fails);
if(fails > P2P_IP_FAILS_BEFORE_BLOCK)
{
- auto it = m_ip_fails_score.find(address);
- CHECK_AND_ASSERT_MES(it != m_ip_fails_score.end(), false, "internal error");
+ auto it = m_host_fails_score.find(address.host_str());
+ CHECK_AND_ASSERT_MES(it != m_host_fails_score.end(), false, "internal error");
it->second = P2P_IP_FAILS_BEFORE_BLOCK/2;
- block_ip(address);
+ block_host(address);
}
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr)
+ bool node_server<t_payload_net_handler>::parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port)
{
- return epee::string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr);
+ return epee::net_utils::create_network_address(pe, node_addr, default_port);
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@@ -306,10 +306,9 @@ namespace nodetool
{
nodetool::peerlist_entry pe = AUTO_VAL_INIT(pe);
pe.id = crypto::rand<uint64_t>();
- bool r = parse_peer_from_string(pe.adr, pr_str);
+ const uint16_t default_port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT;
+ bool r = parse_peer_from_string(pe.adr, pr_str, default_port);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str);
- if (pe.adr.port == 0)
- pe.adr.port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT;
m_command_line_peers.push_back(pe);
}
}
@@ -359,7 +358,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
inline void append_net_address(
- std::vector<net_address> & seed_nodes
+ std::vector<epee::net_utils::network_address> & seed_nodes
, std::string const & addr
)
{
@@ -383,15 +382,14 @@ namespace nodetool
ip::tcp::endpoint endpoint = *i;
if (endpoint.address().is_v4())
{
- nodetool::net_address na;
- na.ip = boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong());
- na.port = endpoint.port();
+ epee::net_utils::network_address na(new epee::net_utils::ipv4_network_address(boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port()));
seed_nodes.push_back(na);
- MINFO("Added seed node: " << endpoint.address().to_v4().to_string(ec) << ':' << na.port);
+ MINFO("Added seed node: " << na.str());
}
else
{
- MDEBUG("IPv6 doesn't supported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec));
+ MERROR("IPv6 unsupported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec));
+ throw std::runtime_error("IPv6 unsupported");
}
}
}
@@ -752,10 +750,10 @@ namespace nodetool
return;
}
- if(!handle_remote_peerlist(rsp.local_peerlist, rsp.node_data.local_time, context))
+ if(!handle_remote_peerlist(rsp.local_peerlist_new, rsp.node_data.local_time, context))
{
LOG_ERROR_CC(context, "COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection.");
- add_ip_fail(context.m_remote_ip);
+ add_host_fail(context.m_remote_address);
return;
}
hsh_result = true;
@@ -769,7 +767,7 @@ namespace nodetool
}
pi = context.peer_id = rsp.node_data.peer_id;
- m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port);
+ m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address);
if(rsp.node_data.peer_id == m_config.m_peer_id)
{
@@ -821,14 +819,14 @@ namespace nodetool
return;
}
- if(!handle_remote_peerlist(rsp.local_peerlist, rsp.local_time, context))
+ if(!handle_remote_peerlist(rsp.local_peerlist_new, rsp.local_time, context))
{
LOG_WARNING_CC(context, "COMMAND_TIMED_SYNC: failed to handle_remote_peerlist(...), closing connection.");
m_net_server.get_config_object().close(context.m_connection_id );
- add_ip_fail(context.m_remote_ip);
+ add_host_fail(context.m_remote_address);
}
if(!context.m_is_income)
- m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_ip, context.m_remote_port);
+ m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_address);
m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false);
});
@@ -863,7 +861,7 @@ namespace nodetool
bool used = false;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr.ip == cntxt.m_remote_ip && peer.adr.port == cntxt.m_remote_port))
+ if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
{
used = true;
return false;//stop enumerating
@@ -885,7 +883,7 @@ namespace nodetool
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr.ip == cntxt.m_remote_ip && peer.adr.port == cntxt.m_remote_port))
+ if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
{
used = true;
@@ -899,12 +897,12 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::is_addr_connected(const net_address& peer)
+ bool node_server<t_payload_net_handler>::is_addr_connected(const epee::net_utils::network_address& peer)
{
bool connected = false;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if(!cntxt.m_is_income && peer.ip == cntxt.m_remote_ip && peer.port == cntxt.m_remote_port)
+ if(!cntxt.m_is_income && peer == cntxt.m_remote_address)
{
connected = true;
return false;//stop enumerating
@@ -925,7 +923,7 @@ namespace nodetool
} while(0)
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
+ bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
{
if (m_current_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit
{
@@ -937,23 +935,24 @@ namespace nodetool
m_current_number_of_out_peers --; // atomic variable, update time = 1s
return false;
}
- MDEBUG("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":"
- << epee::string_tools::num_to_string_fast(na.port) << "(peer_type=" << peer_type << ", last_seen: "
+ MDEBUG("Connecting to " << na.str() << "(peer_type=" << peer_type << ", last_seen: "
<< (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
<< ")...");
+ CHECK_AND_ASSERT_MES(na.type() == typeid(epee::net_utils::ipv4_network_address), false,
+ "Only IPv4 addresses are supported here, got " << na.type().name());
+ const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>();
+
typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
- bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip),
- epee::string_tools::num_to_string_fast(na.port),
+ bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()),
+ epee::string_tools::num_to_string_fast(ipv4.port()),
m_config.m_net_config.connection_timeout,
con);
if(!res)
{
bool is_priority = is_priority_node(na);
- LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to "
- << epee::string_tools::get_ip_string_from_int32(na.ip)
- << ":" << epee::string_tools::num_to_string_fast(na.port)
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " << na.str()
/*<< ", try " << try_count*/);
//m_peerlist.set_peer_unreachable(pe);
return false;
@@ -966,8 +965,7 @@ namespace nodetool
{
bool is_priority = is_priority_node(na);
LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer "
- << epee::string_tools::get_ip_string_from_int32(na.ip)
- << ":" << epee::string_tools::num_to_string_fast(na.port)
+ << na.str()
/*<< ", try " << try_count*/);
return false;
}
@@ -1000,25 +998,26 @@ namespace nodetool
}
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp)
+ bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const epee::net_utils::network_address& na, uint64_t last_seen_stamp)
{
- LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":"
- << epee::string_tools::num_to_string_fast(na.port) << "(last_seen: "
+ LOG_PRINT_L1("Connecting to " << na.str() << "(last_seen: "
<< (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
<< ")...");
+ CHECK_AND_ASSERT_MES(na.type() == typeid(epee::net_utils::ipv4_network_address), false,
+ "Only IPv4 addresses are supported here, got " << na.type().name());
+ const epee::net_utils::ipv4_network_address &ipv4 = na.as<epee::net_utils::ipv4_network_address>();
+
typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
- bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip),
- epee::string_tools::num_to_string_fast(na.port),
+ bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()),
+ epee::string_tools::num_to_string_fast(ipv4.port()),
m_config.m_net_config.connection_timeout,
con);
if (!res) {
bool is_priority = is_priority_node(na);
- LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to "
- << epee::string_tools::get_ip_string_from_int32(na.ip)
- << ":" << epee::string_tools::num_to_string_fast(na.port));
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " << na.str());
return false;
}
@@ -1029,9 +1028,7 @@ namespace nodetool
if (!res) {
bool is_priority = is_priority_node(na);
- LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer "
- << epee::string_tools::get_ip_string_from_int32(na.ip)
- << ":" << epee::string_tools::num_to_string_fast(na.port));
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer " << na.str());
return false;
}
@@ -1047,7 +1044,7 @@ namespace nodetool
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::is_addr_recently_failed(const net_address& addr)
+ bool node_server<t_payload_net_handler>::is_addr_recently_failed(const epee::net_utils::network_address& addr)
{
CRITICAL_REGION_LOCAL(m_conn_fails_cache_lock);
auto it = m_conn_fails_cache.find(addr);
@@ -1064,14 +1061,14 @@ namespace nodetool
bool node_server<t_payload_net_handler>::make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist)
{
for (const auto& pe: anchor_peerlist) {
- _note("Considering connecting (out) to peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port));
+ _note("Considering connecting (out) to peer: " << pe.id << " " << pe.adr.str());
if(is_peer_used(pe)) {
_note("Peer is used");
continue;
}
- if(!is_remote_ip_allowed(pe.adr.ip)) {
+ if(!is_remote_host_allowed(pe.adr)) {
continue;
}
@@ -1079,8 +1076,7 @@ namespace nodetool
continue;
}
- MDEBUG("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip)
- << ":" << boost::lexical_cast<std::string>(pe.adr.port)
+ MDEBUG("Selected peer: " << pe.id << " " << pe.adr.str()
<< "[peer_type=" << anchor
<< "] first_seen: " << epee::misc_utils::get_time_interval_string(time(NULL) - pe.first_seen));
@@ -1131,21 +1127,20 @@ namespace nodetool
++try_count;
- _note("Considering connecting (out) to peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port));
+ _note("Considering connecting (out) to peer: " << pe.id << " " << pe.adr.str());
if(is_peer_used(pe)) {
_note("Peer is used");
continue;
}
- if(!is_remote_ip_allowed(pe.adr.ip))
+ if(!is_remote_host_allowed(pe.adr))
continue;
if(is_addr_recently_failed(pe.adr))
continue;
- MDEBUG("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip)
- << ":" << boost::lexical_cast<std::string>(pe.adr.port)
+ MDEBUG("Selected peer: " << pe.id << " " << pe.adr.str()
<< "[peer_list=" << (use_white_list ? white : gray)
<< "] last_seen: " << (pe.last_seen ? epee::misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never"));
@@ -1329,7 +1324,7 @@ namespace nodetool
{
if(be.last_seen > local_time)
{
- MWARNING("FOUND FUTURE peerlist for entry " << epee::string_tools::get_ip_string_from_int32(be.adr.ip) << ":" << be.adr.port << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time);
+ MWARNING("FOUND FUTURE peerlist for entry " << be.adr.str() << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time);
return false;
}
be.last_seen += delta;
@@ -1425,8 +1420,7 @@ namespace nodetool
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
connection_entry ce;
- ce.adr.ip = cntxt.m_remote_ip;
- ce.adr.port = cntxt.m_remote_port;
+ ce.adr = cntxt.m_remote_address;
ce.id = cntxt.peer_id;
ce.is_income = cntxt.m_is_income;
rsp.connections_list.push_back(ce);
@@ -1516,19 +1510,24 @@ namespace nodetool
if(!node_data.my_port)
return false;
- uint32_t actual_ip = context.m_remote_ip;
- if(!m_peerlist.is_ip_allowed(actual_ip))
+ CHECK_AND_ASSERT_MES(context.m_remote_address.type() == typeid(epee::net_utils::ipv4_network_address), false,
+ "Only IPv4 addresses are supported here, got " << context.m_remote_address.type().name());
+
+ const epee::net_utils::network_address na = context.m_remote_address;
+ uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
+ if(!m_peerlist.is_host_allowed(context.m_remote_address))
return false;
std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip);
std::string port = epee::string_tools::num_to_string_fast(node_data.my_port);
+ epee::net_utils::network_address address(new epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port));
peerid_type pr = node_data.peer_id;
- bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ ip, port, pr, this](
+ bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this](
const typename net_server::t_connection_context& ping_context,
const boost::system::error_code& ec)->bool
{
if(ec)
{
- LOG_WARNING_CC(ping_context, "back ping connect failed to " << ip << ":" << port);
+ LOG_WARNING_CC(ping_context, "back ping connect failed to " << address.str());
return false;
}
COMMAND_PING::request req;
@@ -1547,13 +1546,13 @@ namespace nodetool
{
if(code <= 0)
{
- LOG_ERROR_CC(ping_context, "Failed to invoke COMMAND_PING to " << ip << ":" << port << "(" << code << ", " << epee::levin::get_err_descr(code) << ")");
+ LOG_ERROR_CC(ping_context, "Failed to invoke COMMAND_PING to " << address.str() << "(" << code << ", " << epee::levin::get_err_descr(code) << ")");
return;
}
if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id)
{
- LOG_ERROR_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << ip << ":" << port << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id);
+ LOG_ERROR_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id);
m_net_server.get_config_object().close(ping_context.m_connection_id);
return;
}
@@ -1563,7 +1562,7 @@ namespace nodetool
if(!inv_call_res)
{
- LOG_ERROR_CC(ping_context, "back ping invoke failed to " << ip << ":" << port);
+ LOG_ERROR_CC(ping_context, "back ping invoke failed to " << address.str());
m_net_server.get_config_object().close(ping_context.m_connection_id);
return false;
}
@@ -1614,7 +1613,7 @@ namespace nodetool
//fill response
rsp.local_time = time(NULL);
- m_peerlist.get_peerlist_head(rsp.local_peerlist);
+ m_peerlist.get_peerlist_head(rsp.local_peerlist_new);
m_payload_handler.get_payload_sync_data(rsp.payload_data);
LOG_DEBUG_CC(context, "COMMAND_TIMED_SYNC");
return 1;
@@ -1628,7 +1627,7 @@ namespace nodetool
LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id));
drop_connection(context);
- add_ip_fail(context.m_remote_ip);
+ add_host_fail(context.m_remote_address);
return 1;
}
@@ -1636,7 +1635,7 @@ namespace nodetool
{
LOG_ERROR_CC(context, "COMMAND_HANDSHAKE came not from incoming connection");
drop_connection(context);
- add_ip_fail(context.m_remote_ip);
+ add_host_fail(context.m_remote_address);
return 1;
}
@@ -1654,9 +1653,9 @@ namespace nodetool
return 1;
}
- if(has_too_many_connections(context.m_remote_ip))
+ if(has_too_many_connections(context.m_remote_address))
{
- LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << " REFUSED, too many connections from the same address");
+ LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << context.m_remote_address.host_str() << " REFUSED, too many connections from the same address");
drop_connection(context);
return 1;
}
@@ -1671,16 +1670,18 @@ namespace nodetool
//try ping to be sure that we can add this peer to peer_list
try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]()
{
+ CHECK_AND_ASSERT_MES(context.m_remote_address.type() == typeid(epee::net_utils::ipv4_network_address), void(),
+ "Only IPv4 addresses are supported here, got " << context.m_remote_address.type().name());
//called only(!) if success pinged, update local peerlist
peerlist_entry pe;
- pe.adr.ip = context.m_remote_ip;
- pe.adr.port = port_l;
+ const epee::net_utils::network_address na = context.m_remote_address;
+ pe.adr.reset(new epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l));
time_t last_seen;
time(&last_seen);
pe.last_seen = static_cast<int64_t>(last_seen);
pe.id = peer_id_l;
this->m_peerlist.append_with_peer_white(pe);
- LOG_DEBUG_CC(context, "PING SUCCESS " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l);
+ LOG_DEBUG_CC(context, "PING SUCCESS " << context.m_remote_address.host_str() << ":" << port_l);
});
}
@@ -1690,7 +1691,7 @@ namespace nodetool
});
//fill response
- m_peerlist.get_peerlist_head(rsp.local_peerlist);
+ m_peerlist.get_peerlist_head(rsp.local_peerlist_new);
get_local_node_data(rsp.node_data);
m_payload_handler.get_payload_sync_data(rsp.payload_data);
LOG_DEBUG_CC(context, "COMMAND_HANDSHAKE");
@@ -1730,7 +1731,7 @@ namespace nodetool
std::stringstream ss;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- ss << epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) << ":" << cntxt.m_remote_port
+ ss << cntxt.m_remote_address.str()
<< " \t\tpeer_id " << cntxt.peer_id
<< " \t\tconn_id " << epee::string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT")
<< std::endl;
@@ -1750,9 +1751,8 @@ namespace nodetool
void node_server<t_payload_net_handler>::on_connection_close(p2p_connection_context& context)
{
if (!m_net_server.is_stop_signal_sent() && !context.m_is_income) {
- nodetool::net_address na = AUTO_VAL_INIT(na);
- na.ip = context.m_remote_ip;
- na.port = context.m_remote_port;
+ epee::net_utils::network_address na = AUTO_VAL_INIT(na);
+ na = context.m_remote_address;
m_peerlist.remove_from_peer_anchor(na);
}
@@ -1761,7 +1761,7 @@ namespace nodetool
}
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::is_priority_node(const net_address& na)
+ bool node_server<t_payload_net_handler>::is_priority_node(const epee::net_utils::network_address& na)
{
return (std::find(m_priority_peers.begin(), m_priority_peers.end(), na) != m_priority_peers.end()) || (std::find(m_exclusive_peers.begin(), m_exclusive_peers.end(), na) != m_exclusive_peers.end());
}
@@ -1769,7 +1769,7 @@ namespace nodetool
template<class t_payload_net_handler> template <class Container>
bool node_server<t_payload_net_handler>::connect_to_peerlist(const Container& peers)
{
- for(const net_address& na: peers)
+ for(const epee::net_utils::network_address& na: peers)
{
if(m_net_server.is_stop_signal_sent())
return false;
@@ -1790,11 +1790,10 @@ namespace nodetool
for(const std::string& pr_str: perrs)
{
- nodetool::net_address na = AUTO_VAL_INIT(na);
- bool r = parse_peer_from_string(na, pr_str);
+ epee::net_utils::network_address na = AUTO_VAL_INIT(na);
+ const uint16_t default_port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT;
+ bool r = parse_peer_from_string(na, pr_str, default_port);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str);
- if (na.port == 0)
- na.port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT;
container.push_back(na);
}
@@ -1888,14 +1887,14 @@ namespace nodetool
}
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::has_too_many_connections(const uint32_t ip)
+ bool node_server<t_payload_net_handler>::has_too_many_connections(const epee::net_utils::network_address &address)
{
const uint8_t max_connections = 1;
uint8_t count = 0;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if (cntxt.m_is_income && cntxt.m_remote_ip == ip) {
+ if (cntxt.m_is_income && cntxt.m_remote_address.is_same_host(address)) {
count++;
if (count > max_connections) {
@@ -1923,14 +1922,14 @@ namespace nodetool
if (!success) {
m_peerlist.remove_from_peer_gray(pe);
- LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+ LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << std::hex << pe.id);
return true;
}
m_peerlist.set_peer_just_seen(pe.id, pe.adr);
- LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+ LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << std::hex << pe.id);
return true;
}
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 6aba7aa24..42de2655d 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -51,10 +51,10 @@ 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, uint32_t)> f)=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()=0;
- virtual bool add_ip_fail(uint32_t adress)=0;
+ virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds = 0)=0;
+ virtual bool unblock_host(const epee::net_utils::network_address &address)=0;
+ virtual std::map<std::string, time_t> get_blocked_hosts()=0;
+ virtual bool add_host_fail(const epee::net_utils::network_address &address)=0;
};
template<class t_connection_context>
@@ -93,19 +93,19 @@ namespace nodetool
{
return false;
}
- virtual bool block_ip(uint32_t adress, time_t seconds)
+ virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds)
{
return true;
}
- virtual bool unblock_ip(uint32_t adress)
+ virtual bool unblock_host(const epee::net_utils::network_address &address)
{
return true;
}
- virtual std::map<uint32_t, time_t> get_blocked_ips()
+ virtual std::map<std::string, time_t> get_blocked_hosts()
{
- return std::map<uint32_t, time_t>();
+ return std::map<std::string, time_t>();
}
- virtual bool add_ip_fail(uint32_t adress)
+ virtual bool add_host_fail(const epee::net_utils::network_address &address)
{
return true;
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index de0f51cc3..a30a05422 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -54,7 +54,7 @@
#include "net_peerlist_boost_serialization.h"
-#define CURRENT_PEERLIST_STORAGE_ARCHIVE_VER 5
+#define CURRENT_PEERLIST_STORAGE_ARCHIVE_VER 6
namespace nodetool
{
@@ -78,14 +78,13 @@ namespace nodetool
bool append_with_peer_white(const peerlist_entry& pr);
bool append_with_peer_gray(const peerlist_entry& pr);
bool append_with_peer_anchor(const anchor_peerlist_entry& ple);
- bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port);
- bool set_peer_just_seen(peerid_type peer, const net_address& addr);
+ bool set_peer_just_seen(peerid_type peer, const epee::net_utils::network_address& addr);
bool set_peer_unreachable(const peerlist_entry& pr);
- bool is_ip_allowed(uint32_t ip);
+ bool is_host_allowed(const epee::net_utils::network_address &address);
bool get_random_gray_peer(peerlist_entry& pe);
bool remove_from_peer_gray(const peerlist_entry& pe);
bool get_and_empty_anchor_peerlist(std::vector<anchor_peerlist_entry>& apl);
- bool remove_from_peer_anchor(const net_address& addr);
+ bool remove_from_peer_anchor(const epee::net_utils::network_address& addr);
private:
struct by_time{};
@@ -130,7 +129,7 @@ namespace nodetool
peerlist_entry,
boost::multi_index::indexed_by<
// access by peerlist_entry::net_adress
- boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >,
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,epee::net_utils::network_address,&peerlist_entry::adr> >,
// sort by peerlist_entry::last_seen<
boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,int64_t,&peerlist_entry::last_seen> >
>
@@ -142,7 +141,7 @@ namespace nodetool
// access by peerlist_entry::id<
boost::multi_index::ordered_unique<boost::multi_index::tag<by_id>, boost::multi_index::member<peerlist_entry,uint64_t,&peerlist_entry::id> >,
// access by peerlist_entry::net_adress
- boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >,
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,epee::net_utils::network_address,&peerlist_entry::adr> >,
// sort by peerlist_entry::last_seen<
boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,int64_t,&peerlist_entry::last_seen> >
>
@@ -152,16 +151,45 @@ namespace nodetool
anchor_peerlist_entry,
boost::multi_index::indexed_by<
// access by anchor_peerlist_entry::net_adress
- boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<anchor_peerlist_entry,net_address,&anchor_peerlist_entry::adr> >,
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<anchor_peerlist_entry,epee::net_utils::network_address,&anchor_peerlist_entry::adr> >,
// sort by anchor_peerlist_entry::first_seen
boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<anchor_peerlist_entry,int64_t,&anchor_peerlist_entry::first_seen> >
>
> anchor_peers_indexed;
public:
+ template <class Archive, class List, class Element, class t_version_type>
+ void serialize_peers(Archive &a, List &list, Element ple, const t_version_type ver)
+ {
+ if (typename Archive::is_saving())
+ {
+ uint64_t size = list.size();
+ a & size;
+ for (auto p: list)
+ {
+ a & p;
+ }
+ }
+ else
+ {
+ uint64_t size;
+ a & size;
+ list.clear();
+ while (size--)
+ {
+ a & ple;
+ list.insert(ple);
+ }
+ }
+ }
+
template <class Archive, class t_version_type>
void serialize(Archive &a, const t_version_type ver)
{
+ // at v6, we drop existing peerlists, because annoying change
+ if (ver < 6)
+ return;
+
if(ver < 3)
return;
CRITICAL_REGION_LOCAL(m_peerlist_lock);
@@ -174,14 +202,25 @@ namespace nodetool
return;
}
+#if 0
+ // trouble loading more than one peer, can't find why
a & m_peers_white;
a & m_peers_gray;
+#else
+ serialize_peers(a, m_peers_white, peerlist_entry(), ver);
+ serialize_peers(a, m_peers_gray, peerlist_entry(), ver);
+#endif
if(ver < 5) {
return;
}
+#if 0
+ // trouble loading more than one peer, can't find why
a & m_peers_anchor;
+#else
+ serialize_peers(a, m_peers_anchor, anchor_peerlist_entry(), ver);
+#endif
}
private:
@@ -284,13 +323,13 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::is_ip_allowed(uint32_t ip)
+ bool peerlist_manager::is_host_allowed(const epee::net_utils::network_address &address)
{
//never allow loopback ip
- if(epee::net_utils::is_ip_loopback(ip))
+ if(address.is_loopback())
return false;
- if(!m_allow_local_ip && epee::net_utils::is_ip_local(ip))
+ if(!m_allow_local_ip && address.is_local())
return false;
return true;
@@ -336,16 +375,7 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port)
- {
- net_address addr;
- addr.ip = ip;
- addr.port = port;
- return set_peer_just_seen(peer, addr);
- }
- //--------------------------------------------------------------------------------------------------
- inline
- bool peerlist_manager::set_peer_just_seen(peerid_type peer, const net_address& addr)
+ bool peerlist_manager::set_peer_just_seen(peerid_type peer, const epee::net_utils::network_address& addr)
{
TRY_ENTRY();
CRITICAL_REGION_LOCAL(m_peerlist_lock);
@@ -362,7 +392,7 @@ namespace nodetool
bool peerlist_manager::append_with_peer_white(const peerlist_entry& ple)
{
TRY_ENTRY();
- if(!is_ip_allowed(ple.adr.ip))
+ if(!is_host_allowed(ple.adr))
return true;
CRITICAL_REGION_LOCAL(m_peerlist_lock);
@@ -392,7 +422,7 @@ namespace nodetool
bool peerlist_manager::append_with_peer_gray(const peerlist_entry& ple)
{
TRY_ENTRY();
- if(!is_ip_allowed(ple.adr.ip))
+ if(!is_host_allowed(ple.adr))
return true;
CRITICAL_REGION_LOCAL(m_peerlist_lock);
@@ -496,7 +526,7 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::remove_from_peer_anchor(const net_address& addr)
+ bool peerlist_manager::remove_from_peer_anchor(const epee::net_utils::network_address& addr)
{
TRY_ENTRY();
diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h
index 6891ac80c..0a21895cf 100644
--- a/src/p2p/net_peerlist_boost_serialization.h
+++ b/src/p2p/net_peerlist_boost_serialization.h
@@ -30,16 +30,43 @@
#pragma once
+#include "net/net_utils_base.h"
+
namespace boost
{
namespace serialization
{
- //BOOST_CLASS_VERSION(odetool::net_adress, 1)
+ enum { sertype_ipv4_address };
+ static inline uint8_t get_type(const epee::net_utils::network_address &na)
+ {
+ if (na.type() == typeid(epee::net_utils::ipv4_network_address))
+ return sertype_ipv4_address;
+ throw std::runtime_error("Unsupported network address type");
+ return 0;
+ }
+ template <class Archive, class ver_type>
+ inline void serialize(Archive &a, epee::net_utils::network_address& na, const ver_type ver)
+ {
+ uint8_t type;
+ if (typename Archive::is_saving())
+ type = get_type(na);
+ a & type;
+ switch (type)
+ {
+ case sertype_ipv4_address:
+ if (!typename Archive::is_saving())
+ na.reset(new epee::net_utils::ipv4_network_address(0, 0));
+ a & na.as<epee::net_utils::ipv4_network_address>();
+ break;
+ default:
+ throw std::runtime_error("Unsupported network address type");
+ }
+ }
template <class Archive, class ver_type>
- inline void serialize(Archive &a, nodetool::net_address& na, const ver_type ver)
+ inline void serialize(Archive &a, epee::net_utils::ipv4_network_address& na, const ver_type ver)
{
- a & na.ip;
- a & na.port;
+ a & na.m_ip;
+ a & na.m_port;
}
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index 5ec012714..d60990f8a 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -32,6 +32,7 @@
#include <boost/uuid/uuid.hpp>
#include "serialization/keyvalue_serialization.h"
+#include "net/net_utils_base.h"
#include "misc_language.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
@@ -43,46 +44,64 @@ namespace nodetool
#pragma pack (push, 1)
- struct net_address
+ struct network_address_old
{
uint32_t ip;
uint32_t port;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(ip)
+ KV_SERIALIZE(port)
+ END_KV_SERIALIZE_MAP()
};
- struct peerlist_entry
+ template<typename AddressType>
+ struct peerlist_entry_base
{
- net_address adr;
+ AddressType adr;
peerid_type id;
int64_t last_seen;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(adr)
+ KV_SERIALIZE(id)
+ KV_SERIALIZE(last_seen)
+ END_KV_SERIALIZE_MAP()
};
+ typedef peerlist_entry_base<epee::net_utils::network_address> peerlist_entry;
- struct anchor_peerlist_entry
+ template<typename AddressType>
+ struct anchor_peerlist_entry_base
{
- net_address adr;
+ AddressType adr;
peerid_type id;
int64_t first_seen;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(adr)
+ KV_SERIALIZE(id)
+ KV_SERIALIZE(first_seen)
+ END_KV_SERIALIZE_MAP()
};
+ typedef anchor_peerlist_entry_base<epee::net_utils::network_address> anchor_peerlist_entry;
- struct connection_entry
+ template<typename AddressType>
+ struct connection_entry_base
{
- net_address adr;
+ AddressType adr;
peerid_type id;
bool is_income;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(adr)
+ KV_SERIALIZE(id)
+ KV_SERIALIZE(is_income)
+ END_KV_SERIALIZE_MAP()
};
+ typedef connection_entry_base<epee::net_utils::network_address> connection_entry;
#pragma pack(pop)
- inline
- bool operator < (const net_address& a, const net_address& b)
- {
- return epee::misc_utils::is_less_as_pod(a, b);
- }
-
- inline
- bool operator == (const net_address& a, const net_address& b)
- {
- return memcmp(&a, &b, sizeof(a)) == 0;
- }
inline
std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl)
{
@@ -92,7 +111,7 @@ namespace nodetool
ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase;
for(const peerlist_entry& pe: pl)
{
- ss << pe.id << "\t" << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port) << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl;
+ ss << pe.id << "\t" << pe.adr->str() << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl;
}
return ss.str();
}
@@ -157,12 +176,40 @@ namespace nodetool
{
basic_node_data node_data;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist;
+ std::list<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(node_data)
KV_SERIALIZE(payload_data)
- KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist)
+ if (is_store)
+ {
+ // saving: save both, so old and new peers can understand it
+ KV_SERIALIZE(local_peerlist_new)
+ std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ for (const auto &p: this_ref.local_peerlist_new)
+ {
+ if (p.adr.type() == typeid(epee::net_utils::ipv4_network_address))
+ {
+ const epee::net_utils::network_address &na = p.adr;
+ const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>();
+ local_peerlist.push_back(peerlist_entry_base<network_address_old>({{ipv4.ip(), ipv4.port()}, p.id, p.last_seen}));
+ }
+ else
+ MDEBUG("Not including in legacy peer list: " << p.adr.str());
+ }
+ epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
+ }
+ else
+ {
+ // loading: load old list only if there is no new one
+ if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
+ {
+ std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
+ for (const auto &p: local_peerlist)
+ ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
+ }
+ }
END_KV_SERIALIZE_MAP()
};
};
@@ -188,12 +235,40 @@ namespace nodetool
{
uint64_t local_time;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist;
+ std::list<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(local_time)
KV_SERIALIZE(payload_data)
- KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist)
+ if (is_store)
+ {
+ // saving: save both, so old and new peers can understand it
+ KV_SERIALIZE(local_peerlist_new)
+ std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ for (const auto &p: this_ref.local_peerlist_new)
+ {
+ if (p.adr.type() == typeid(epee::net_utils::ipv4_network_address))
+ {
+ const epee::net_utils::network_address &na = p.adr;
+ const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>();
+ local_peerlist.push_back(peerlist_entry_base<network_address_old>({{ipv4.ip(), ipv4.port()}, p.id, p.last_seen}));
+ }
+ else
+ MDEBUG("Not including in legacy peer list: " << p.adr.str());
+ }
+ epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
+ }
+ else
+ {
+ // loading: load old list only if there is no new one
+ if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
+ {
+ std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
+ for (const auto &p: local_peerlist)
+ ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
+ }
+ }
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 43891458c..7dc5a1fd9 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -736,12 +736,20 @@ namespace cryptonote
for (auto & entry : white_list)
{
- res.white_list.emplace_back(entry.id, entry.adr.ip, entry.adr.port, entry.last_seen);
+ if (entry.adr.type() == typeid(epee::net_utils::ipv4_network_address))
+ 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);
+ else
+ res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen);
}
for (auto & entry : gray_list)
{
- res.gray_list.emplace_back(entry.id, entry.adr.ip, entry.adr.port, entry.last_seen);
+ if (entry.adr.type() == typeid(epee::net_utils::ipv4_network_address))
+ 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);
+ else
+ res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen);
}
res.status = CORE_RPC_STATUS_OK;
@@ -1308,12 +1316,16 @@ namespace cryptonote
}
auto now = time(nullptr);
- 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)
+ std::map<std::string, time_t> blocked_hosts = m_p2p.get_blocked_hosts();
+ for (std::map<std::string, time_t>::const_iterator i = blocked_hosts.begin(); i != blocked_hosts.end(); ++i)
{
if (i->second > now) {
COMMAND_RPC_GETBANS::ban b;
- b.ip = i->first;
+ b.host = i->first;
+ b.ip = 0;
+ uint32_t ip;
+ if (epee::string_tools::get_ip_int32_from_string(ip, i->first))
+ b.ip = ip;
b.seconds = i->second - now;
res.bans.push_back(b);
}
@@ -1334,10 +1346,24 @@ namespace cryptonote
for (auto i = req.bans.begin(); i != req.bans.end(); ++i)
{
+ epee::net_utils::network_address na;
+ if (!i->host.empty())
+ {
+ if (!epee::net_utils::create_network_address(na, i->host))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "Unsupported host type";
+ return false;
+ }
+ }
+ else
+ {
+ na.reset(new epee::net_utils::ipv4_network_address(i->ip, 0));
+ }
if (i->ban)
- m_p2p.block_ip(i->ip, i->seconds);
+ m_p2p.block_host(na, i->seconds);
else
- m_p2p.unblock_ip(i->ip);
+ m_p2p.unblock_host(na);
}
res.status = CORE_RPC_STATUS_OK;
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 8b5f189ca..7a1f5a963 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 11
+#define CORE_RPC_VERSION_MINOR 12
#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)
@@ -861,18 +861,23 @@ namespace cryptonote
struct peer {
uint64_t id;
+ std::string host;
uint32_t ip;
uint16_t port;
uint64_t last_seen;
peer() = default;
+ peer(uint64_t id, const std::string &host, uint64_t last_seen)
+ : id(id), host(host), ip(0), port(0), last_seen(last_seen)
+ {}
peer(uint64_t id, uint32_t ip, uint16_t port, uint64_t last_seen)
- : id(id), ip(ip), port(port), last_seen(last_seen)
+ : id(id), host(std::to_string(ip)), ip(ip), port(port), last_seen(last_seen)
{}
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id)
+ KV_SERIALIZE(host)
KV_SERIALIZE(ip)
KV_SERIALIZE(port)
KV_SERIALIZE(last_seen)
@@ -1047,6 +1052,17 @@ namespace cryptonote
};
};
+ struct txpool_histo
+ {
+ uint32_t txs;
+ uint64_t bytes;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(txs)
+ KV_SERIALIZE(bytes)
+ END_KV_SERIALIZE_MAP()
+ };
+
struct txpool_stats
{
uint64_t bytes_total;
@@ -1058,6 +1074,8 @@ namespace cryptonote
uint32_t num_failing;
uint32_t num_10m;
uint32_t num_not_relayed;
+ uint64_t histo_98pc;
+ std::vector<txpool_histo> histo;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(bytes_total)
@@ -1069,6 +1087,8 @@ namespace cryptonote
KV_SERIALIZE(num_failing)
KV_SERIALIZE(num_10m)
KV_SERIALIZE(num_not_relayed)
+ KV_SERIALIZE(histo_98pc)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(histo)
END_KV_SERIALIZE_MAP()
};
@@ -1271,10 +1291,12 @@ namespace cryptonote
{
struct ban
{
+ std::string host;
uint32_t ip;
uint32_t seconds;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(host)
KV_SERIALIZE(ip)
KV_SERIALIZE(seconds)
END_KV_SERIALIZE_MAP()
@@ -1302,11 +1324,13 @@ namespace cryptonote
{
struct ban
{
+ std::string host;
uint32_t ip;
bool ban;
uint32_t seconds;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(host)
KV_SERIALIZE(ip)
KV_SERIALIZE(ban)
KV_SERIALIZE(seconds)
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 87dbcf513..4d53f063e 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -47,6 +47,7 @@
#include "common/command_line.h"
#include "common/util.h"
#include "common/dns_utils.h"
+#include "common/base58.h"
#include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "simplewallet.h"
@@ -398,6 +399,19 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ crypto::hash payment_id;
+ if (args.size() > 0)
+ {
+ fail_msg_writer() << tr("usage: payment_id");
+ return true;
+ }
+ payment_id = crypto::rand<crypto::hash>();
+ success_msg_writer() << tr("Random payment ID: ") << payment_id;
+ return true;
+}
+
bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -701,6 +715,8 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs"));
m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), tr("Get transaction key (r) for a given <txid>"));
m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>"));
+ m_cmd_binder.set_handler("get_tx_proof", boost::bind(&simple_wallet::get_tx_proof, this, _1), tr("Generate a signature to prove payment to <address> in <txid> using the transaction secret key (r) without revealing it"));
+ m_cmd_binder.set_handler("check_tx_proof", boost::bind(&simple_wallet::check_tx_proof, this, _1), tr("Check tx proof for payment going to <address> in <txid>"));
m_cmd_binder.set_handler("show_transfers", boost::bind(&simple_wallet::show_transfers, this, _1), tr("show_transfers [in|out|pending|failed|pool] [<min_height> [<max_height>]] - Show incoming/outgoing transfers within an optional height range"));
m_cmd_binder.set_handler("unspent_outputs", boost::bind(&simple_wallet::unspent_outputs, this, _1), tr("unspent_outputs [<min_amount> <max_amount>] - Show unspent outputs within an optional amount range)"));
m_cmd_binder.set_handler("rescan_bc", boost::bind(&simple_wallet::rescan_blockchain, this, _1), tr("Rescan blockchain from scratch"));
@@ -715,6 +731,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("import_outputs", boost::bind(&simple_wallet::import_outputs, this, _1), tr("Import set of outputs owned by this wallet"));
m_cmd_binder.set_handler("show_transfer", boost::bind(&simple_wallet::show_transfer, this, _1), tr("Show information about a transfer to/from this address"));
m_cmd_binder.set_handler("password", boost::bind(&simple_wallet::change_password, this, _1), tr("Change wallet password"));
+ m_cmd_binder.set_handler("payment_id", boost::bind(&simple_wallet::payment_id, this, _1), tr("Generate a new random full size payment id - these will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids"));
m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help"));
}
//----------------------------------------------------------------------------------------------------
@@ -929,6 +946,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet and --non-deterministic");
return false;
}
+ if (!m_wallet_file.empty())
+ {
+ fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file");
+ return false;
+ }
if (m_electrum_seed.empty())
{
@@ -1090,6 +1112,10 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
else
{
+ if (m_generate_new.empty()) {
+ fail_msg_writer() << tr("specify a wallet path with --generate-new-wallet (not --wallet-file)");
+ return false;
+ }
m_wallet_file = m_generate_new;
bool r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
@@ -1167,7 +1193,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
bool r = open_wallet(vm);
CHECK_AND_ASSERT_MES(r, false, tr("failed to open account"));
}
- assert(m_wallet);
+ if (!m_wallet)
+ {
+ fail_msg_writer() << tr("wallet is null");
+ return false;
+ }
// set --trusted-daemon if local
try
@@ -1547,7 +1577,11 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
if (!try_connect_to_daemon())
return true;
- assert(m_wallet);
+ if (!m_wallet)
+ {
+ fail_msg_writer() << tr("wallet is null");
+ return true;
+ }
COMMAND_RPC_START_MINING::request req = AUTO_VAL_INIT(req);
req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->testnet());
@@ -1590,7 +1624,11 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args)
if (!try_connect_to_daemon())
return true;
- assert(m_wallet);
+ if (!m_wallet)
+ {
+ fail_msg_writer() << tr("wallet is null");
+ return true;
+ }
COMMAND_RPC_STOP_MINING::request req;
COMMAND_RPC_STOP_MINING::response res;
bool r = net_utils::invoke_http_json("/stop_mining", req, res, m_http_client);
@@ -1607,7 +1645,11 @@ bool simple_wallet::save_bc(const std::vector<std::string>& args)
if (!try_connect_to_daemon())
return true;
- assert(m_wallet);
+ if (!m_wallet)
+ {
+ fail_msg_writer() << tr("wallet is null");
+ return true;
+ }
COMMAND_RPC_SAVE_BC::request req;
COMMAND_RPC_SAVE_BC::response res;
bool r = net_utils::invoke_http_json("/save_bc", req, res, m_http_client);
@@ -3209,6 +3251,85 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
}
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
+{
+ if(args.size() != 2 && args.size() != 3) {
+ fail_msg_writer() << tr("usage: get_tx_proof <txid> <dest_address> [<tx_key>]");
+ return true;
+ }
+ if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(args[0], txid_data) || txid_data.size() != sizeof(crypto::hash))
+ {
+ fail_msg_writer() << tr("failed to parse txid");
+ return true;
+ }
+ crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ cryptonote::account_public_address address;
+ bool has_payment_id;
+ crypto::hash8 payment_id;
+ if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), args[1]))
+ {
+ fail_msg_writer() << tr("failed to parse address");
+ return true;
+ }
+
+ LOCK_IDLE_SCOPE();
+
+ crypto::secret_key tx_key, tx_key2;
+ bool r = m_wallet->get_tx_key(txid, tx_key);
+ cryptonote::blobdata tx_key_data;
+ if (args.size() == 3)
+ {
+ if(!epee::string_tools::parse_hexstr_to_binbuff(args[2], tx_key_data) || tx_key_data.size() != sizeof(crypto::secret_key))
+ {
+ fail_msg_writer() << tr("failed to parse tx_key");
+ return true;
+ }
+ tx_key2 = *reinterpret_cast<const crypto::secret_key*>(tx_key_data.data());
+ }
+ if (r)
+ {
+ if (args.size() == 3 && tx_key != rct::sk2rct(tx_key2))
+ {
+ fail_msg_writer() << tr("Tx secret key was found for the given txid, but you've also provided another tx secret key which doesn't match the found one.");
+ return true;
+ }
+ }
+ else
+ {
+ if (tx_key_data.empty())
+ {
+ fail_msg_writer() << tr("Tx secret key wasn't found in the wallet file. Provide it as the optional third parameter if you have it elsewhere.");
+ return true;
+ }
+ tx_key = tx_key2;
+ }
+
+ crypto::public_key R;
+ crypto::secret_key_to_public_key(tx_key, R);
+ crypto::public_key rA = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)));
+ crypto::signature sig;
+ try
+ {
+ crypto::generate_tx_proof(txid, R, address.m_view_public_key, rA, tx_key, sig);
+ }
+ catch (const std::runtime_error &e)
+ {
+ fail_msg_writer() << e.what();
+ return true;
+ }
+
+ std::string sig_str = std::string("ProofV1") +
+ tools::base58::encode(std::string((const char *)&rA, sizeof(crypto::public_key))) +
+ tools::base58::encode(std::string((const char *)&sig, sizeof(crypto::signature)));
+
+ success_msg_writer() << tr("Signature: ") << sig_str;
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
{
std::vector<std::string> local_args = args_;
@@ -3221,7 +3342,11 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
if (!try_connect_to_daemon())
return true;
- assert(m_wallet);
+ if (!m_wallet)
+ {
+ fail_msg_writer() << tr("wallet is null");
+ return true;
+ }
cryptonote::blobdata txid_data;
if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[0], txid_data) || txid_data.size() != sizeof(crypto::hash))
{
@@ -3230,8 +3355,6 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
}
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
- LOCK_IDLE_SCOPE();
-
if (local_args[1].size() < 64 || local_args[1].size() % 64)
{
fail_msg_writer() << tr("failed to parse tx key");
@@ -3255,6 +3378,18 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
return true;
}
+ crypto::key_derivation derivation;
+ if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation))
+ {
+ fail_msg_writer() << tr("failed to generate key derivation from supplied parameters");
+ return true;
+ }
+
+ return check_tx_key_helper(txid, address, derivation);
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::check_tx_key_helper(const crypto::hash &txid, const cryptonote::account_public_address &address, const crypto::key_derivation &derivation)
+{
COMMAND_RPC_GET_TRANSACTIONS::request req;
COMMAND_RPC_GET_TRANSACTIONS::response res;
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
@@ -3288,13 +3423,6 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
return true;
}
- crypto::key_derivation derivation;
- if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation))
- {
- fail_msg_writer() << tr("failed to generate key derivation from supplied parameters");
- return true;
- }
-
uint64_t received = 0;
try {
for (size_t n = 0; n < tx.vout.size(); ++n)
@@ -3317,14 +3445,6 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
{
rct::key Ctmp;
//rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)));
- crypto::key_derivation derivation;
- bool r = crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation);
- if (!r)
- {
- LOG_ERROR("Failed to generate key derivation to decode rct output " << n);
- amount = 0;
- }
- else
{
crypto::secret_key scalar1;
crypto::derivation_to_scalar(derivation, n, scalar1);
@@ -3381,6 +3501,129 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
+{
+ if(args.size() != 3) {
+ fail_msg_writer() << tr("usage: check_tx_proof <txid> <address> <signature>");
+ return true;
+ }
+
+ if (!try_connect_to_daemon())
+ return true;
+
+ // parse txid
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(args[0], txid_data) || txid_data.size() != sizeof(crypto::hash))
+ {
+ fail_msg_writer() << tr("failed to parse txid");
+ return true;
+ }
+ crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ // parse address
+ cryptonote::account_public_address address;
+ bool has_payment_id;
+ crypto::hash8 payment_id;
+ if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), args[1]))
+ {
+ fail_msg_writer() << tr("failed to parse address");
+ return true;
+ }
+
+ // parse pubkey r*A & signature
+ std::string sig_str = args[2];
+ const size_t header_len = strlen("ProofV1");
+ if (sig_str.size() < header_len || sig_str.substr(0, header_len) != "ProofV1")
+ {
+ fail_msg_writer() << tr("Signature header check error");
+ return true;
+ }
+ crypto::public_key rA;
+ crypto::signature sig;
+ const size_t rA_len = tools::base58::encode(std::string((const char *)&rA, sizeof(crypto::public_key))).size();
+ const size_t sig_len = tools::base58::encode(std::string((const char *)&sig, sizeof(crypto::signature))).size();
+ std::string rA_decoded;
+ std::string sig_decoded;
+ if (!tools::base58::decode(sig_str.substr(header_len, rA_len), rA_decoded))
+ {
+ fail_msg_writer() << tr("Signature decoding error");
+ return true;
+ }
+ if (!tools::base58::decode(sig_str.substr(header_len + rA_len, sig_len), sig_decoded))
+ {
+ fail_msg_writer() << tr("Signature decoding error");
+ return true;
+ }
+ if (sizeof(crypto::public_key) != rA_decoded.size() || sizeof(crypto::signature) != sig_decoded.size())
+ {
+ fail_msg_writer() << tr("Signature decoding error");
+ return true;
+ }
+ memcpy(&rA, rA_decoded.data(), sizeof(crypto::public_key));
+ memcpy(&sig, sig_decoded.data(), sizeof(crypto::signature));
+
+ // fetch tx pubkey from the daemon
+ COMMAND_RPC_GET_TRANSACTIONS::request req;
+ COMMAND_RPC_GET_TRANSACTIONS::response res;
+ req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
+ if (!net_utils::invoke_http_json("/gettransactions", req, res, m_http_client) ||
+ (res.txs.size() != 1 && res.txs_as_hex.size() != 1))
+ {
+ fail_msg_writer() << tr("failed to get transaction from daemon");
+ return true;
+ }
+ cryptonote::blobdata tx_data;
+ bool ok;
+ if (res.txs.size() == 1)
+ ok = string_tools::parse_hexstr_to_binbuff(res.txs.front().as_hex, tx_data);
+ else
+ ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
+ if (!ok)
+ {
+ fail_msg_writer() << tr("failed to parse transaction from daemon");
+ return true;
+ }
+ crypto::hash tx_hash, tx_prefix_hash;
+ cryptonote::transaction tx;
+ if (!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash))
+ {
+ fail_msg_writer() << tr("failed to validate transaction from daemon");
+ return true;
+ }
+ if (tx_hash != txid)
+ {
+ fail_msg_writer() << tr("failed to get the right transaction from daemon");
+ return true;
+ }
+ crypto::public_key R = get_tx_pub_key_from_extra(tx);
+ if (R == null_pkey)
+ {
+ fail_msg_writer() << tr("Tx pubkey was not found");
+ return true;
+ }
+
+ // check signature
+ if (crypto::check_tx_proof(txid, R, address.m_view_public_key, rA, sig))
+ {
+ success_msg_writer() << tr("Good signature");
+ }
+ else
+ {
+ fail_msg_writer() << tr("Bad signature");
+ return true;
+ }
+
+ // obtain key derivation by multiplying scalar 1 to the pubkey r*A included in the signature
+ crypto::key_derivation derivation;
+ if (!crypto::generate_key_derivation(rA, rct::rct2sk(rct::I), derivation))
+ {
+ fail_msg_writer() << tr("failed to generate key derivation");
+ return true;
+ }
+
+ return check_tx_key_helper(txid, address, derivation);
+}
+//----------------------------------------------------------------------------------------------------
static std::string get_human_readable_timestamp(uint64_t ts)
{
char buffer[64];
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 1b58ff32a..e04352295 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -154,6 +154,9 @@ namespace cryptonote
bool set_log(const std::vector<std::string> &args);
bool get_tx_key(const std::vector<std::string> &args);
bool check_tx_key(const std::vector<std::string> &args);
+ bool check_tx_key_helper(const crypto::hash &txid, const cryptonote::account_public_address &address, const crypto::key_derivation &derivation);
+ bool get_tx_proof(const std::vector<std::string> &args);
+ bool check_tx_proof(const std::vector<std::string> &args);
bool show_transfers(const std::vector<std::string> &args);
bool unspent_outputs(const std::vector<std::string> &args);
bool rescan_blockchain(const std::vector<std::string> &args);
@@ -170,6 +173,7 @@ namespace cryptonote
bool import_outputs(const std::vector<std::string> &args);
bool show_transfer(const std::vector<std::string> &args);
bool change_password(const std::vector<std::string>& args);
+ bool payment_id(const std::vector<std::string> &args);
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 1b4300edf..6a0e1727c 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -144,7 +144,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid)
+ virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
{
// TODO;
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 96ba04c47..ee2b6055c 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -511,6 +511,7 @@ bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::
{
if(m_http_client.is_connected())
m_http_client.disconnect();
+ m_is_initialized = true;
m_upper_transaction_size_limit = upper_transaction_size_limit;
m_daemon_address = std::move(daemon_address);
m_daemon_login = std::move(daemon_login);
@@ -1845,6 +1846,7 @@ void wallet2::detach_blockchain(uint64_t height)
//----------------------------------------------------------------------------------------------------
bool wallet2::deinit()
{
+ m_is_initialized=false;
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -2361,6 +2363,8 @@ bool wallet2::prepare_file_names(const std::string& file_path)
//----------------------------------------------------------------------------------------------------
bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
{
+ THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
+
boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
if(!m_http_client.is_connected())
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index bde233b33..e7692badb 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -105,7 +105,7 @@ namespace tools
};
private:
- wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
+ wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false),m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
public:
static const char* tr(const char* str);
@@ -129,7 +129,7 @@ namespace tools
//! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm);
- wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
+ wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
struct transfer_details
{
@@ -695,6 +695,7 @@ namespace tools
uint32_t m_min_output_count;
uint64_t m_min_output_value;
bool m_merge_destinations;
+ bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
};
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index 3e3578149..16807e045 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -49,6 +49,7 @@ namespace tools
// wallet_runtime_error *
// wallet_internal_error
// unexpected_txin_type
+ // wallet_not_initialized
// std::logic_error
// wallet_logic_error *
// file_exists
@@ -177,6 +178,15 @@ namespace tools
cryptonote::transaction m_tx;
};
//----------------------------------------------------------------------------------------------------
+ struct wallet_not_initialized : public wallet_internal_error
+ {
+ explicit wallet_not_initialized(std::string&& loc)
+ : wallet_internal_error(std::move(loc), "wallet is not initialized")
+ {
+ }
+ };
+
+ //----------------------------------------------------------------------------------------------------
const char* const file_error_messages[] = {
"file already exists",
"file not found",
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index add48eebe..7cad04047 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -472,6 +472,7 @@ inline bool do_replay_events(std::vector<test_event_entry>& events)
MERROR("Failed to init core");
return false;
}
+ c.get_blockchain_storage().get_db().set_batch_transactions(true);
// start with a clean pool
std::vector<crypto::hash> pool_txs;
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index 4bfe90733..febf8b2f7 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -118,6 +118,7 @@ public:
virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; }
virtual void remove_txpool_tx(const crypto::hash& txid) {}
virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const { return txpool_tx_meta_t(); }
+ virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; }
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false) const { return false; }