diff --git a/.gitignore b/.gitignore index 554267b09..20a3894a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .DS_Store /build -/tags \ No newline at end of file +/tags diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d367b2e1..28130e566 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,11 @@ else() else() set(DEBUG_FLAGS "-g3 -O0") endif() - set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable -flto") + set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable") + if(NOT APPLE) + # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled + set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto") + endif() #if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) # set(RELEASE_FLAGS "${RELEASE_FLAGS} -fno-fat-lto-objects") #endif() @@ -77,8 +81,8 @@ else() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") - if(STATIC) - set_static_flags() + if(STATIC AND NOT APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") endif() endif() @@ -86,7 +90,7 @@ if(STATIC) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) endif() -find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization atomic program_options) +find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options) if((${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54)) message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA") endif() diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 3aa32a238..78e8af157 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -1,5 +1,19 @@ Bitmonero +Release notes 0.8.8 + +- JSON RPC v2.0 compatibility +- JSON RPC over TCP added- Further optimizations +- Fixed a bug with checkpoints behavior +- UI improvements for daemon +- Fixed COIN value (10^12) +- Raised minimum fee to 5 * (10^9) +- Temporary fix for block reward DoS attack + +Release notes 0.8.7 + +- Slow hash optimizations + Release notes 0.8.6 - Simplwallet can set extra for transfers @@ -21,17 +35,13 @@ Release notes 0.8.4 Release notes 0.8.3 - JSON RPC for wallet -- fixed bug with blockchain storing -- fixed bug with correct display of transfer's change -- bug fix in simple wallet +- Fixed bug with blockchain storing +- Fixed bug with correct display of transfer's change +- Bug fix in simple wallet Release notes 0.8.2 -- now wallet is still working when daemon stores blockchain and can't serve clients; -- no-console option for a daemon; -- fixed problem with network synchronization; -- major bug fix in simple wallet. - -Release notes 0.8.1 - -Bytecoin project is moved to GitHub \ No newline at end of file +- Now wallet is still working when daemon stores blockchain and can't serve clients +- No-console option for a daemon +- Fixed problem with network synchronization +- Major bug fix in simple wallet diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index 5798d2def..fcab35aaa 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -267,23 +267,6 @@ namespace epee if(0 == command.compare("exit") || 0 == command.compare("q")) { continue_handle = false; - }else if (!command.compare(0, 7, "set_log")) - { - //parse set_log command - if(command.size() != 9) - { - std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; - continue; - } - uint16_t n = 0; - if(!string_tools::get_xtype_from_string(n, command.substr(8, 1))) - { - std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; - continue; - } - log_space::get_set_log_detalisation_level(true, n); - std::cout << "New log level set " << n; - LOG_PRINT_L2("New log level set " << n); }else if (command.empty()) { continue; diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 2a4b10e48..403f5a3bd 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -52,11 +52,11 @@ PRAGMA_WARNING_DISABLE_VS(4355) typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter* &pfilter) : strand_(io_service), socket_(io_service), - m_protocol_handler(this, config, context), m_want_close_connection(0), m_was_shutdown(0), m_ref_sockets_count(sock_count), - m_pfilter(pfilter) + m_pfilter(pfilter), + m_protocol_handler(this, config, context) { boost::interprocess::ipcdetail::atomic_inc32(&m_ref_sockets_count); } diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h index 4bf48750e..aed909778 100644 --- a/contrib/epee/include/net/http_protocol_handler.h +++ b/contrib/epee/include/net/http_protocol_handler.h @@ -55,20 +55,20 @@ namespace net_utils /************************************************************************/ /* */ /************************************************************************/ - template + template class simple_http_connection_handler { public: - typedef t_connection_context connection_context;//t_connection_context net_utils::connection_context_base connection_context; + typedef t_connection_context connection_context;//t_connection_context net_utils::connection_context_base connection_context; typedef http_server_config config_type; simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config); virtual ~simple_http_connection_handler(){} - bool release_protocol() - { - return true; - } + bool release_protocol() + { + return true; + } virtual bool thread_init() { @@ -85,10 +85,6 @@ namespace net_utils } virtual bool handle_recv(const void* ptr, size_t cb); virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response); - - - //temporary here - //bool parse_uri(const std::string uri, uri_content& content); private: enum machine_state{ @@ -142,34 +138,37 @@ namespace net_utils i_service_endpoint* m_psnd_hndlr; }; - template + template struct i_http_server_handler { virtual ~i_http_server_handler(){} - virtual bool handle_http_request(const http_request_info& query_info, http_response_info& response, t_connection_context& m_conn_context)=0; - virtual bool init_server_thread(){return true;} + virtual bool handle_http_request(const http_request_info& query_info, + http_response_info& response, + t_connection_context& m_conn_context) = 0; + virtual bool init_server_thread(){return true;} virtual bool deinit_server_thread(){return true;} }; - template + template struct custum_handler_config: public http_server_config { i_http_server_handler* m_phandler; }; - /************************************************************************/ - /* */ - /************************************************************************/ + /************************************************************************/ + /* */ + /************************************************************************/ - template + template class http_custom_handler: public simple_http_connection_handler { public: typedef custum_handler_config config_type; - http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context):simple_http_connection_handler(psnd_hndlr, config), - m_config(config), - m_conn_context(conn_context) + http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context) + : simple_http_connection_handler(psnd_hndlr, config), + m_config(config), + m_conn_context(conn_context) {} inline bool handle_request(const http_request_info& query_info, http_response_info& response) { @@ -191,8 +190,8 @@ namespace net_utils { return m_config.m_phandler->deinit_server_thread(); } - void handle_qued_callback() - {} + void handle_qued_callback() + {} bool after_init_connection() { return true; diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index af4e035f8..201460130 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -26,9 +26,10 @@ #pragma once -#include "serialization/keyvalue_serialization.h" -#include "storages/portable_storage_template_helper.h" #include "http_base.h" +#include "jsonrpc_structs.h" +#include "storages/portable_storage.h" +#include "storages/portable_storage_template_helper.h" #define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \ @@ -109,98 +110,6 @@ #define END_URI_MAP2() return handled;} - - -namespace epee -{ - namespace json_rpc - { - template - struct request - { - std::string jsonrpc; - std::string method; - epee::serialization::storage_entry id; - t_param params; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(jsonrpc) - KV_SERIALIZE(id) - KV_SERIALIZE(method) - KV_SERIALIZE(params) - END_KV_SERIALIZE_MAP() - }; - - struct error - { - int64_t code; - std::string message; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(code) - KV_SERIALIZE(message) - END_KV_SERIALIZE_MAP() - }; - - struct dummy_error - { - BEGIN_KV_SERIALIZE_MAP() - END_KV_SERIALIZE_MAP() - }; - - struct dummy_result - { - BEGIN_KV_SERIALIZE_MAP() - END_KV_SERIALIZE_MAP() - }; - - template - struct response - { - std::string jsonrpc; - t_param result; - epee::serialization::storage_entry id; - t_error error; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(jsonrpc) - KV_SERIALIZE(id) - KV_SERIALIZE(result) - KV_SERIALIZE(error) - END_KV_SERIALIZE_MAP() - }; - - template - struct response - { - std::string jsonrpc; - t_param result; - epee::serialization::storage_entry id; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(jsonrpc) - KV_SERIALIZE(id) - KV_SERIALIZE(result) - END_KV_SERIALIZE_MAP() - }; - - template - struct response - { - std::string jsonrpc; - t_error error; - epee::serialization::storage_entry id; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(jsonrpc) - KV_SERIALIZE(id) - KV_SERIALIZE(error) - END_KV_SERIALIZE_MAP() - }; - - typedef response error_response; - } -} - - - - #define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == uri) \ { \ uint64_t ticks = epee::misc_utils::get_tick_count(); \ @@ -315,6 +224,6 @@ namespace epee rsp.error.message = "Method not found"; \ epee::serialization::store_t_to_json(static_cast(rsp), response_info.m_body); \ return true; \ - } +} diff --git a/contrib/epee/include/net/jsonrpc_protocol_handler.h b/contrib/epee/include/net/jsonrpc_protocol_handler.h new file mode 100644 index 000000000..b224c3429 --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_protocol_handler.h @@ -0,0 +1,167 @@ +#ifndef JSONRPC_PROTOCOL_HANDLER_H +#define JSONRPC_PROTOCOL_HANDLER_H + +#include +#include + +#include "net/net_utils_base.h" +#include "jsonrpc_structs.h" +#include "storages/portable_storage.h" +#include "storages/portable_storage_template_helper.h" + +namespace epee +{ +namespace net_utils +{ + namespace jsonrpc2 + { + inline + std::string& make_error_resp_json(int64_t code, const std::string& message, + std::string& response_data, + const epee::serialization::storage_entry& id = nullptr) + { + epee::json_rpc::error_response rsp; + rsp.id = id; + rsp.jsonrpc = "2.0"; + rsp.error.code = code; + rsp.error.message = message; + epee::serialization::store_t_to_json(static_cast(rsp), response_data, 0, false); + response_data += "\n"; + return response_data; + } + + template + struct i_jsonrpc2_server_handler + { + virtual ~i_jsonrpc2_server_handler() + {} + virtual bool handle_rpc_request(const std::string& req_data, + std::string& resp_data, + t_connection_context& conn_context) = 0; + virtual bool init_server_thread() + { return true; } + virtual bool deinit_server_thread() + { return true; } + }; + + template + struct jsonrpc2_server_config + { + i_jsonrpc2_server_handler* m_phandler; + critical_section m_lock; + }; + + template + class jsonrpc2_connection_handler + { + public: + typedef t_connection_context connection_context; + typedef jsonrpc2_server_config config_type; + + jsonrpc2_connection_handler(i_service_endpoint* psnd_hndlr, + config_type& config, + t_connection_context& conn_context) + : m_psnd_hndlr(psnd_hndlr), + m_config(config), + m_conn_context(conn_context), + m_is_stop_handling(false) + {} + virtual ~jsonrpc2_connection_handler() + {} + + bool release_protocol() + { + return true; + } + virtual bool thread_init() + { + return true; + } + virtual bool thread_deinit() + { + return true; + } + void handle_qued_callback() + {} + bool after_init_connection() + { + return true; + } + virtual bool handle_recv(const void* ptr, size_t cb) + { + std::string buf((const char*)ptr, cb); + LOG_PRINT_L0("JSONRPC2_RECV: " << ptr << "\r\n" << buf); + + bool res = handle_buff_in(buf); + return res; + } + private: + bool handle_buff_in(std::string& buf) + { + if(m_cache.size()) + m_cache += buf; + else + m_cache.swap(buf); + + m_is_stop_handling = false; + while (!m_is_stop_handling) { + std::string::size_type pos = match_end_of_request(m_cache); + if (std::string::npos == pos) { + m_is_stop_handling = true; + if (m_cache.size() > 4096) { + LOG_ERROR("jsonrpc2_connection_handler::handle_buff_in: Too long request"); + return false; + } + break; + } else { + extract_cached_request_and_handle(pos); + } + + if (!m_cache.size()) { + m_is_stop_handling = true; + } + } + + return true; + } + bool extract_cached_request_and_handle(std::string::size_type pos) + { + std::string request_data(m_cache.begin(), m_cache.begin() + pos); + m_cache.erase(0, pos); + return handle_request_and_send_response(request_data); + } + bool handle_request_and_send_response(const std::string& request_data) + { + CHECK_AND_ASSERT_MES(m_config.m_phandler, false, "m_config.m_phandler is NULL!!!!"); + std::string response_data; + + LOG_PRINT_L3("JSONRPC2_REQUEST: >> \r\n" << request_data); + bool rpc_result = m_config.m_phandler->handle_rpc_request(request_data, response_data, m_conn_context); + LOG_PRINT_L3("JSONRPC2_RESPONSE: << \r\n" << response_data); + + m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size()); + return rpc_result; + } + std::string::size_type match_end_of_request(const std::string& buf) + { + std::string::size_type res = buf.find("\n"); + if(std::string::npos != res) { + return res + 2; + } + return res; + } + + protected: + i_service_endpoint* m_psnd_hndlr; + + private: + config_type& m_config; + t_connection_context& m_conn_context; + std::string m_cache; + bool m_is_stop_handling; + }; + } +} +} + +#endif /* JSONRPC_PROTOCOL_HANDLER_H */ diff --git a/contrib/epee/include/net/jsonrpc_server_handlers_map.h b/contrib/epee/include/net/jsonrpc_server_handlers_map.h new file mode 100644 index 000000000..8c747d1af --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_server_handlers_map.h @@ -0,0 +1,86 @@ +#ifndef JSONRPC_SERVER_HANDLERS_MAP_H +#define JSONRPC_SERVER_HANDLERS_MAP_H + +#include +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "storages/portable_storage_base.h" +#include "jsonrpc_structs.h" +#include "jsonrpc_protocol_handler.h" + +#define BEGIN_JSONRPC2_MAP(t_connection_context) \ +bool handle_rpc_request(const std::string& req_data, \ + std::string& resp_data, \ + t_connection_context& m_conn_context) \ +{ \ + bool handled = false; \ + uint64_t ticks = epee::misc_utils::get_tick_count(); \ + epee::serialization::portable_storage ps; \ + if (!ps.load_from_json(req_data)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32700, "Parse error", resp_data); \ + return true; \ + } \ + epee::serialization::storage_entry id_; \ + id_ = epee::serialization::storage_entry(std::string()); \ + if (!ps.get_value("id", id_, nullptr)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32600, "Invalid Request", resp_data); \ + return true; \ + } \ + std::string callback_name; \ + if (!ps.get_value("method", callback_name, nullptr)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32600, "Invalid Request", resp_data, id_); \ + return true; \ + } \ + if (false) return true; //just a stub to have "else if" + + + +#define PREPARE_JSONRPC2_OBJECTS_FROM_JSON(command_type) \ + handled = true; \ + boost::value_initialized > req_; \ + epee::json_rpc::request& req = static_cast&>(req_);\ + if(!req.load(ps)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32602, "Invalid params", resp_data, req.id); \ + return true; \ + } \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + boost::value_initialized > resp_; \ + epee::json_rpc::response& resp = static_cast &>(resp_); \ + resp.jsonrpc = "2.0"; \ + resp.id = req.id; + +#define FINALIZE_JSONRPC2_OBJECTS_TO_JSON(method_name) \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + epee::serialization::store_t_to_json(resp, resp_data, 0, false); \ + resp_data += "\n"; \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + LOG_PRINT("[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); + + +#define MAP_JSONRPC2_WE(method_name, callback_f, command_type) \ + else if (callback_name == method_name) \ + { \ + PREPARE_JSONRPC2_OBJECTS_FROM_JSON(command_type) \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.id = req.id; \ + if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \ + { \ + epee::serialization::store_t_to_json(static_cast(fail_resp), resp_data, 0, false); \ + resp_data += "\n"; \ + return true; \ + } \ + FINALIZE_JSONRPC2_OBJECTS_TO_JSON(method_name) \ + return true; \ + } + +#define END_JSONRPC2_MAP() \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32601, "Method not found", resp_data, id_); \ + return true; \ +} + +#endif /* JSONRPC_SERVER_HANDLERS_MAP_H */ diff --git a/contrib/epee/include/net/jsonrpc_server_impl_base.h b/contrib/epee/include/net/jsonrpc_server_impl_base.h new file mode 100644 index 000000000..8a5a9a5b6 --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_server_impl_base.h @@ -0,0 +1,84 @@ +#ifndef JSONRPC_SERVER_IMPL_BASE_H +#define JSONRPC_SERVER_IMPL_BASE_H + +#include +#include + +#include "net/jsonrpc_protocol_handler.h" +#include "net/jsonrpc_server_handlers_map.h" +#include "net/abstract_tcp_server2.h" + +namespace epee +{ + +template + class jsonrpc_server_impl_base: public net_utils::jsonrpc2::i_jsonrpc2_server_handler + { + + public: + jsonrpc_server_impl_base() + : m_net_server() + {} + + explicit jsonrpc_server_impl_base(boost::asio::io_service& external_io_service) + : m_net_server(external_io_service) + {} + + bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0") + { + //set self as callback handler + m_net_server.get_config_object().m_phandler = static_cast(this); + + LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); + bool res = m_net_server.init_server(bind_port, bind_ip); + if (!res) + { + LOG_ERROR("Failed to bind server"); + return false; + } + return true; + } + + bool run(size_t threads_count, bool wait = true) + { + //go to loop + LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(threads_count, wait)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + if(wait) + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + return true; + } + + bool deinit() + { + return m_net_server.deinit_server(); + } + + bool timed_wait_server_stop(uint64_t ms) + { + return m_net_server.timed_wait_server_stop(ms); + } + + bool send_stop_signal() + { + m_net_server.send_stop_signal(); + return true; + } + + int get_binded_port() + { + return m_net_server.get_binded_port(); + } + + protected: + net_utils::boosted_tcp_server > m_net_server; + }; + +} + +#endif /* JSONRPC_SERVER_IMPL_BASE_H */ + diff --git a/contrib/epee/include/net/jsonrpc_structs.h b/contrib/epee/include/net/jsonrpc_structs.h new file mode 100644 index 000000000..9df9e2596 --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_structs.h @@ -0,0 +1,96 @@ +#ifndef JSONRPC_STRUCTS_H +#define JSONRPC_STRUCTS_H + +#include +#include +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_base.h" + +namespace epee +{ + namespace json_rpc + { + template + struct request + { + std::string jsonrpc; + std::string method; + epee::serialization::storage_entry id; + t_param params; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(method) + KV_SERIALIZE(params) + END_KV_SERIALIZE_MAP() + }; + + struct error + { + int64_t code; + std::string message; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(code) + KV_SERIALIZE(message) + END_KV_SERIALIZE_MAP() + }; + + struct dummy_error + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct dummy_result + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_param result; + epee::serialization::storage_entry id; + t_error error; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(result) + KV_SERIALIZE(error) + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_param result; + epee::serialization::storage_entry id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(result) + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_error error; + epee::serialization::storage_entry id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(error) + END_KV_SERIALIZE_MAP() + }; + + typedef response error_response; + } +} + +#endif /* JSONRPC_STRUCTS_H */ diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index 793135b87..b5619bab3 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -47,8 +47,8 @@ namespace net_utils struct connection_context_base { const boost::uuids::uuid m_connection_id; - const uint32_t m_remote_ip; - const uint32_t m_remote_port; + const uint32_t m_remote_ip; + const uint32_t m_remote_port; const bool m_is_income; const time_t m_started; time_t m_last_recv; @@ -56,27 +56,30 @@ namespace net_utils uint64_t m_recv_cnt; uint64_t m_send_cnt; - connection_context_base(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income, time_t last_recv = 0, time_t last_send = 0, uint64_t recv_cnt = 0, uint64_t send_cnt = 0): + connection_context_base(boost::uuids::uuid connection_id, + long remote_ip, int remote_port, 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_is_income(is_income), + m_started(time(NULL)), m_last_recv(last_recv), m_last_send(last_send), m_recv_cnt(recv_cnt), - m_send_cnt(send_cnt), - m_started(time(NULL)) + m_send_cnt(send_cnt) {} connection_context_base(): m_connection_id(), m_remote_ip(0), m_remote_port(0), m_is_income(false), + m_started(time(NULL)), m_last_recv(0), m_last_send(0), m_recv_cnt(0), - m_send_cnt(0), - m_started(time(NULL)) + m_send_cnt(0) {} connection_context_base& operator=(const connection_context_base& a) diff --git a/contrib/epee/include/profile_tools.h b/contrib/epee/include/profile_tools.h index be45feafe..0e1646f60 100644 --- a/contrib/epee/include/profile_tools.h +++ b/contrib/epee/include/profile_tools.h @@ -51,13 +51,13 @@ namespace epee #define PROFILE_FUNC_THIRD(immortal_ptr_str) #endif -#define START_WAY_POINTS() uint64_t _____way_point_time = misc_utils::get_tick_count(); -#define WAY_POINT(name) {uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} -#define WAY_POINT2(name, avrg_obj) {uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} +#define START_WAY_POINTS() uint64_t _____way_point_time = epee::misc_utils::get_tick_count(); +#define WAY_POINT(name) {uint64_t delta = epee::misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} +#define WAY_POINT2(name, avrg_obj) {uint64_t delta = epee::misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} -#define TIME_MEASURE_START(var_name) uint64_t var_name = misc_utils::get_tick_count(); -#define TIME_MEASURE_FINISH(var_name) var_name = misc_utils::get_tick_count() - var_name; +#define TIME_MEASURE_START(var_name) uint64_t var_name = epee::misc_utils::get_tick_count(); +#define TIME_MEASURE_FINISH(var_name) var_name = epee::misc_utils::get_tick_count() - var_name; namespace profile_tools { diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h index 27fb0f1e2..bf2c8dacd 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization.h +++ b/contrib/epee/include/serialization/keyvalue_serialization.h @@ -31,6 +31,8 @@ #include "misc_log_ex.h" #include "enableable.h" #include "keyvalue_serialization_overloads.h" +#include "serialization/serialization.h" + namespace epee { /************************************************************************/ @@ -41,12 +43,12 @@ public: \ template \ bool store( t_storage& st, typename t_storage::hsection hparent_section = nullptr) const\ {\ - return serialize_map(*this, st, hparent_section);\ + return serialize_map(*this, st, hparent_section);\ }\ template \ bool _load( t_storage& stg, typename t_storage::hsection hparent_section = nullptr)\ {\ - return serialize_map(*this, stg, hparent_section);\ + return serialize_map(*this, stg, hparent_section);\ }\ template \ bool load( t_storage& stg, typename t_storage::hsection hparent_section = nullptr)\ diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h index c244dac19..bbfe5f85c 100644 --- a/contrib/epee/include/storages/portable_storage.h +++ b/contrib/epee/include/storages/portable_storage.h @@ -83,7 +83,7 @@ namespace epee bool load_from_binary(const binarybuffer& target); template bool dump_as_xml(std::string& targetObj, const std::string& root_name = ""); - bool dump_as_json(std::string& targetObj, size_t indent = 0); + bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true); bool load_from_json(const std::string& source); private: @@ -106,17 +106,17 @@ namespace epee #pragma pack(pop) }; inline - bool portable_storage::dump_as_json(std::string& buff, size_t indent) + bool portable_storage::dump_as_json(std::string& buff, size_t indent, bool insert_newlines) { TRY_ENTRY(); std::stringstream ss; - epee::serialization::dump_as_json(ss, m_root, indent); + epee::serialization::dump_as_json(ss, m_root, indent, insert_newlines); buff = ss.str(); return true; CATCH_ENTRY("portable_storage::dump_as_json", false) } inline - bool portable_storage::load_from_json(const std::string& source) + bool portable_storage::load_from_json(const std::string& source) { TRY_ENTRY(); return json::load_from_json(source, *this); @@ -124,13 +124,13 @@ namespace epee } template - bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name) + bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name) { return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format } inline - bool portable_storage::store_to_binary(binarybuffer& target) + bool portable_storage::store_to_binary(binarybuffer& target) { TRY_ENTRY(); std::stringstream ss; @@ -145,7 +145,7 @@ namespace epee CATCH_ENTRY("portable_storage::store_to_binary", false) } inline - bool portable_storage::load_from_binary(const binarybuffer& source) + bool portable_storage::load_from_binary(const binarybuffer& source) { m_root.m_entries.clear(); if(source.size() < sizeof(storage_block_header)) @@ -174,7 +174,7 @@ namespace epee } //--------------------------------------------------------------------------------------------------------------- inline - hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist) + hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist) { TRY_ENTRY(); hparent_section = hparent_section ? hparent_section:&m_root; @@ -238,7 +238,7 @@ namespace epee } //--------------------------------------------------------------------------------------------------------------- template - bool portable_storage::set_value(const std::string& value_name, const t_value& v, hsection hparent_section) + bool portable_storage::set_value(const std::string& value_name, const t_value& v, hsection hparent_section) { BOOST_MPL_ASSERT(( boost::mpl::contains::type, t_value> )); TRY_ENTRY(); @@ -345,7 +345,7 @@ namespace epee template - bool portable_storage::get_next_value(harray hval_array, t_value& target) + bool portable_storage::get_next_value(harray hval_array, t_value& target) { BOOST_MPL_ASSERT(( boost::mpl::contains )); //TRY_ENTRY(); @@ -462,7 +462,7 @@ namespace epee } //--------------------------------------------------------------------------------------------------------------- inline - bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection) + bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection) { TRY_ENTRY(); CHECK_AND_ASSERT(hsec_array, false); @@ -476,4 +476,4 @@ namespace epee } //--------------------------------------------------------------------------------------------------------------- } -} \ No newline at end of file +} diff --git a/contrib/epee/include/storages/portable_storage_template_helper.h b/contrib/epee/include/storages/portable_storage_template_helper.h index 2163cb879..008f44321 100644 --- a/contrib/epee/include/storages/portable_storage_template_helper.h +++ b/contrib/epee/include/storages/portable_storage_template_helper.h @@ -25,6 +25,9 @@ // #pragma once + +#include + #include "parserse_base_utils.h" #include "portable_storage.h" #include "file_io_utils.h" @@ -56,19 +59,19 @@ namespace epee } //----------------------------------------------------------------------------------------------------------- template - bool store_t_to_json(t_struct& str_in, std::string& json_buff, size_t indent = 0) + bool store_t_to_json(t_struct& str_in, std::string& json_buff, size_t indent = 0, bool insert_newlines = true) { portable_storage ps; str_in.store(ps); - ps.dump_as_json(json_buff, indent); + ps.dump_as_json(json_buff, indent, insert_newlines); return true; } //----------------------------------------------------------------------------------------------------------- template - std::string store_t_to_json(t_struct& str_in, size_t indent = 0) + std::string store_t_to_json(t_struct& str_in, size_t indent = 0, bool insert_newlines = true) { std::string json_buff; - store_t_to_json(str_in, json_buff, indent); + store_t_to_json(str_in, json_buff, indent, insert_newlines); return std::move(json_buff); } //----------------------------------------------------------------------------------------------------------- diff --git a/contrib/epee/include/storages/portable_storage_to_json.h b/contrib/epee/include/storages/portable_storage_to_json.h index aff85b201..e3fdcec29 100644 --- a/contrib/epee/include/storages/portable_storage_to_json.h +++ b/contrib/epee/include/storages/portable_storage_to_json.h @@ -30,6 +30,7 @@ #include "misc_language.h" #include "portable_storage_base.h" +#include "parserse_base_utils.h" namespace epee { @@ -37,21 +38,21 @@ namespace epee { template - void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent); + void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent); + void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const std::string& v, size_t indent); + void dump_as_json(t_stream& strm, const std::string& v, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const int8_t& v, size_t indent); + void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent); + void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const bool& v, size_t indent); + void dump_as_json(t_stream& strm, const bool& v, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const t_type& v, size_t indent); + void dump_as_json(t_stream& strm, const t_type& v, size_t indent, bool insert_newlines); template - void dump_as_json(t_stream& strm, const section& sec, size_t indent); + void dump_as_json(t_stream& strm, const section& sec, size_t indent, bool insert_newlines); inline std::string make_indent(size_t indent) @@ -64,7 +65,11 @@ namespace epee { t_stream& m_strm; size_t m_indent; - array_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent){} + bool m_insert_newlines; + array_entry_store_to_json_visitor(t_stream& strm, size_t indent, + bool insert_newlines = true) + : m_strm(strm), m_indent(indent), m_insert_newlines(insert_newlines) + {} template void operator()(const array_entry_t& a) @@ -75,7 +80,7 @@ namespace epee auto last_it = --a.m_array.end(); for(auto it = a.m_array.begin(); it != a.m_array.end(); it++) { - dump_as_json(m_strm, *it, m_indent); + dump_as_json(m_strm, *it, m_indent, m_insert_newlines); if(it != last_it) m_strm << ","; } @@ -89,50 +94,53 @@ namespace epee { t_stream& m_strm; size_t m_indent; - storage_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent) + bool m_insert_newlines; + storage_entry_store_to_json_visitor(t_stream& strm, size_t indent, + bool insert_newlines = true) + : m_strm(strm), m_indent(indent), m_insert_newlines(insert_newlines) {} //section, array_entry template void operator()(const visited_type& v) { - dump_as_json(m_strm, v, m_indent); + dump_as_json(m_strm, v, m_indent, m_insert_newlines); } }; template - void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent) + void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, bool insert_newlines) { - array_entry_store_to_json_visitor aesv(strm, indent); + array_entry_store_to_json_visitor aesv(strm, indent, insert_newlines); boost::apply_visitor(aesv, ae); } template - void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent) + void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, bool insert_newlines) { - storage_entry_store_to_json_visitor sv(strm, indent); + storage_entry_store_to_json_visitor sv(strm, indent, insert_newlines); boost::apply_visitor(sv, se); } template - void dump_as_json(t_stream& strm, const std::string& v, size_t indent) + void dump_as_json(t_stream& strm, const std::string& v, size_t indent, bool insert_newlines) { strm << "\"" << misc_utils::parse::transform_to_escape_sequence(v) << "\""; } template - void dump_as_json(t_stream& strm, const int8_t& v, size_t indent) + void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, bool insert_newlines) { strm << static_cast(v); } template - void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent) + void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, bool insert_newlines) { strm << static_cast(v); } template - void dump_as_json(t_stream& strm, const bool& v, size_t indent) + void dump_as_json(t_stream& strm, const bool& v, size_t indent, bool insert_newlines) { if(v) strm << "true"; @@ -143,16 +151,17 @@ namespace epee template - void dump_as_json(t_stream& strm, const t_type& v, size_t indent) + void dump_as_json(t_stream& strm, const t_type& v, size_t indent, bool insert_newlines) { strm << v; } template - void dump_as_json(t_stream& strm, const section& sec, size_t indent) + void dump_as_json(t_stream& strm, const section& sec, size_t indent, bool insert_newlines) { size_t local_indent = indent + 1; - strm << "{\r\n"; + std::string newline = insert_newlines ? "\r\n" : ""; + strm << "{" << newline; std::string indent_str = make_indent(local_indent); if(sec.m_entries.size()) { @@ -160,10 +169,10 @@ namespace epee for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++) { strm << indent_str << "\"" << misc_utils::parse::transform_to_escape_sequence(it->first) << "\"" << ": "; - dump_as_json(strm, it->second, local_indent); + dump_as_json(strm, it->second, local_indent, insert_newlines); if(it_last != it) strm << ","; - strm << "\r\n"; + strm << newline; } } strm << make_indent(indent) << "}"; diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 4cc88418c..8289ee0ba 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -32,6 +32,7 @@ //#include #include #include +#include //#include #include #include diff --git a/src/crypto/oaes_lib.c b/src/crypto/oaes_lib.c index 96f038600..f3f2aac8c 100644 --- a/src/crypto/oaes_lib.c +++ b/src/crypto/oaes_lib.c @@ -64,7 +64,6 @@ static const char _NR[] = { # define min(a,b) (((a)<(b)) ? (a) : (b)) #endif /* min */ - // "OAES<8-bit header version><8-bit type><16-bit options><8-bit flags><56-bit reserved>" static uint8_t oaes_header[OAES_BLOCK_SIZE] = { // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, diff --git a/src/crypto/oaes_lib.h b/src/crypto/oaes_lib.h index 16b914c7a..fd1942822 100644 --- a/src/crypto/oaes_lib.h +++ b/src/crypto/oaes_lib.h @@ -32,6 +32,7 @@ #define _OAES_LIB_H #include +#include #ifdef __cplusplus extern "C" { @@ -101,15 +102,14 @@ typedef int ( * oaes_step_cb ) ( typedef uint16_t OAES_OPTION; - typedef struct _oaes_key { - size_t data_len; - uint8_t *data; - size_t exp_data_len; - uint8_t *exp_data; - size_t num_keys; - size_t key_base; + size_t data_len; + uint8_t *data; + size_t exp_data_len; + uint8_t *exp_data; + size_t num_keys; + size_t key_base; } oaes_key; typedef struct _oaes_ctx @@ -119,14 +119,13 @@ typedef struct _oaes_ctx #endif // OAES_HAVE_ISAAC #ifdef OAES_DEBUG - oaes_step_cb step_cb; + oaes_step_cb step_cb; #endif // OAES_DEBUG - oaes_key * key; - OAES_OPTION options; - uint8_t iv[OAES_BLOCK_SIZE]; + oaes_key * key; + OAES_OPTION options; + uint8_t iv[OAES_BLOCK_SIZE]; } oaes_ctx; - /* * // usage: * diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 34d053aa8..a992a9db0 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -8,7 +8,7 @@ #define CRYPTONOTE_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used! #define CRYPTONOTE_MAX_TX_SIZE 1000000000 #define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0 -#define CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX 18 // addresses start with "2" +#define CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX 18 // addresses start with "4" #define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60 #define CURRENT_TRANSACTION_VERSION 1 #define CURRENT_BLOCK_MAJOR_VERSION 1 @@ -26,8 +26,8 @@ #define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE 600 #define CRYPTONOTE_DISPLAY_DECIMAL_POINT 12 // COIN - number of smallest units in one coin -#define COIN ((uint64_t)100000000) // pow(10, 8) -#define DEFAULT_FEE ((uint64_t)1000000) // pow(10, 6) +#define COIN ((uint64_t)1000000000000) // pow(10, 12) +#define DEFAULT_FEE ((uint64_t)5000000000) // 5 * pow(10, 9) #define ORPHANED_BLOCKS_MAX_COUNT 100 diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index 0e20b454b..9e9c77e85 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -372,7 +372,7 @@ bool blockchain_storage::rollback_blockchain_switching(std::list& origina return true; } //------------------------------------------------------------------ -bool blockchain_storage::switch_to_alternative_blockchain(std::list& alt_chain) +bool blockchain_storage::switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain) { CRITICAL_REGION_LOCAL(m_blockchain_lock); CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed"); @@ -414,16 +414,19 @@ bool blockchain_storage::switch_to_alternative_blockchain(std::list(); - bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc); - if(!r) + //pushing old chain as alternative chain + BOOST_FOREACH(auto& old_ch_ent, disconnected_chain) { - LOG_ERROR("Failed to push ex-main chain blocks to alternative chain "); - rollback_blockchain_switching(disconnected_chain, split_height); - return false; + block_verification_context bvc = boost::value_initialized(); + bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc); + if(!r) + { + LOG_ERROR("Failed to push ex-main chain blocks to alternative chain "); + rollback_blockchain_switching(disconnected_chain, split_height); + return false; + } } } @@ -701,6 +704,22 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: { CRITICAL_REGION_LOCAL(m_blockchain_lock); + uint64_t block_height = get_block_height(b); + if(0 == block_height) + { + LOG_ERROR("Block with id: " << string_tools::pod_to_hex(id) << " (as alternative) have wrong miner transaction"); + bvc.m_verifivation_failed = true; + return false; + } + if (!m_checkpoints.is_alternative_block_allowed(get_current_blockchain_height(), block_height)) + { + LOG_PRINT_RED_L0("Block with id: " << id + << ENDL << " can't be accepted for alternative chain, block height: " << block_height + << ENDL << " blockchain height: " << get_current_blockchain_height()); + bvc.m_verifivation_failed = true; + return false; + } + //block is not related with head of main chain //first of all - look in alternative chains container auto it_main_prev = m_blocks_index.find(b.prev_id); @@ -746,31 +765,28 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: block_extended_info bei = boost::value_initialized(); bei.bl = b; bei.height = alt_chain.size() ? it_prev->second.height + 1 : it_main_prev->second + 1; + + bool is_a_checkpoint; + if(!m_checkpoints.check_block(bei.height, id, is_a_checkpoint)) + { + LOG_ERROR("CHECKPOINT VALIDATION FAILED"); + bvc.m_verifivation_failed = true; + return false; + } + + // Always check PoW for alternative blocks + m_is_in_checkpoint_zone = false; difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei); CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); crypto::hash proof_of_work = null_hash; - if(!m_checkpoints.is_in_checkpoint_zone(bei.height)) + get_block_longhash(bei.bl, proof_of_work, bei.height); + if(!check_hash(proof_of_work, current_diff)) { - m_is_in_checkpoint_zone = false; - get_block_longhash(bei.bl, proof_of_work, bei.height); - - if(!check_hash(proof_of_work, current_diff)) - { - LOG_PRINT_RED_L0("Block with id: " << id - << ENDL << " for alternative chain, have not enough proof of work: " << proof_of_work - << ENDL << " expected difficulty: " << current_diff); - bvc.m_verifivation_failed = true; - return false; - } - }else - { - m_is_in_checkpoint_zone = true; - if(!m_checkpoints.check_block(bei.height, id)) - { - LOG_ERROR("CHECKPOINT VALIDATION FAILED"); - bvc.m_verifivation_failed = true; - return false; - } + LOG_PRINT_RED_L0("Block with id: " << id + << ENDL << " for alternative chain, have not enough proof of work: " << proof_of_work + << ENDL << " expected difficulty: " << current_diff); + bvc.m_verifivation_failed = true; + return false; } if(!prevalidate_miner_transaction(b, bei.height)) @@ -792,22 +808,33 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: auto i_res = m_alternative_chains.insert(blocks_ext_by_hash::value_type(id, bei)); CHECK_AND_ASSERT_MES(i_res.second, false, "insertion of new alternative block returned as it already exist"); alt_chain.push_back(i_res.first); - //check if difficulty bigger then in main chain - if(m_blocks.back().cumulative_difficulty < bei.cumulative_difficulty) + + if(is_a_checkpoint) { //do reorganize! - LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_blocks.size() -1 << " with cum_difficulty " << m_blocks.back().cumulative_difficulty - << ENDL << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty, LOG_LEVEL_0); - bool r = switch_to_alternative_blockchain(alt_chain); + LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_blocks.size() - 1 << + ", checkpoint is found in alternative chain on height " << bei.height, LOG_LEVEL_0); + bool r = switch_to_alternative_blockchain(alt_chain, true); if(r) bvc.m_added_to_main_chain = true; else bvc.m_verifivation_failed = true; return r; + }else if(m_blocks.back().cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain + { + //do reorganize! + LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_blocks.size() - 1 << " with cum_difficulty " << m_blocks.back().cumulative_difficulty + << ENDL << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty, LOG_LEVEL_0); + bool r = switch_to_alternative_blockchain(alt_chain, false); + if(r) bvc.m_added_to_main_chain = true; + else bvc.m_verifivation_failed = true; + return r; + }else + { + LOG_PRINT_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << bei.height + << ENDL << "id:\t" << id + << ENDL << "PoW:\t" << proof_of_work + << ENDL << "difficulty:\t" << current_diff, LOG_LEVEL_0); + return true; } - LOG_PRINT_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << bei.height - << ENDL << "id:\t" << id - << ENDL << "PoW:\t" << proof_of_work - << ENDL << "difficulty:\t" << current_diff, LOG_LEVEL_0); - return true; }else { //block orphaned @@ -815,7 +842,6 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: LOG_PRINT_RED_L0("Block recognized as orphaned and rejected, id = " << id); } - return true; } //------------------------------------------------------------------ @@ -1480,19 +1506,27 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt TIME_MEASURE_FINISH(target_calculating_time); TIME_MEASURE_START(longhash_calculating_time); crypto::hash proof_of_work = null_hash; - if(!m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height())) - { - proof_of_work = get_block_longhash(bl, m_blocks.size()); - if(!check_hash(proof_of_work, current_diffic)) - { - LOG_PRINT_L0("Block with id: " << id << ENDL - << "have not enough proof of work: " << proof_of_work << ENDL - << "nexpected difficulty: " << current_diffic ); - bvc.m_verifivation_failed = true; - return false; - } - }else + // Formerly the code below contained an if loop with the following condition + // !m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height()) + // however, this caused the daemon to not bother checking PoW for blocks + // before checkpoints, which is very dangerous behaviour. We moved the PoW + // validation out of the next chunk of code to make sure that we correctly + // check PoW now. + proof_of_work = get_block_longhash(bl, m_blocks.size()); + + if(!check_hash(proof_of_work, current_diffic)) + { + LOG_PRINT_L0("Block with id: " << id << ENDL + << "have not enough proof of work: " << proof_of_work << ENDL + << "nexpected difficulty: " << current_diffic ); + bvc.m_verifivation_failed = true; + return false; + } + + // If we're at a checkpoint, ensure that our hardcoded checkpoint hash + // is correct. + if(m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height())) { if(!m_checkpoints.check_block(get_current_blockchain_height(), id)) { @@ -1501,6 +1535,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt return false; } } + TIME_MEASURE_FINISH(longhash_calculating_time); if(!prevalidate_miner_transaction(bl, m_blocks.size())) @@ -1648,4 +1683,4 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont } return handle_block_to_main_chain(bl, id, bvc); -} \ No newline at end of file +} diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index 1ea5e29ea..b1fb5df41 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -13,6 +13,8 @@ #include #include +#include "syncobj.h" +#include "string_tools.h" #include "tx_pool.h" #include "cryptonote_basic.h" #include "common/util.h" @@ -50,7 +52,7 @@ namespace cryptonote uint64_t already_generated_coins; }; - blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false) + blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false) {}; bool init() { return init(tools::get_default_data_dir()); } @@ -119,7 +121,7 @@ namespace cryptonote missed_bs.push_back(bl_id); else { - CHECK_AND_ASSERT_MES(it->second < m_blocks.size(), false, "Internal error: bl_id=" << string_tools::pod_to_hex(bl_id) + CHECK_AND_ASSERT_MES(it->second < m_blocks.size(), false, "Internal error: bl_id=" << epee::string_tools::pod_to_hex(bl_id) << " have index record with offset="<second<< ", bigger then m_blocks.size()=" << m_blocks.size()); blocks.push_back(m_blocks[it->second].bl); } @@ -163,7 +165,7 @@ namespace cryptonote typedef std::map>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction tx_memory_pool& m_tx_pool; - critical_section m_blockchain_lock; // TODO: add here reader/writer lock + epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock // main chain blocks_container m_blocks; // height -> block_extended_info @@ -186,7 +188,7 @@ namespace cryptonote std::atomic m_is_in_checkpoint_zone; std::atomic m_is_blockchain_storing; - bool switch_to_alternative_blockchain(std::list& alt_chain); + bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); bool pop_block_from_blockchain(); bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count); bool purge_transaction_from_blockchain(const crypto::hash& tx_id); @@ -301,7 +303,7 @@ namespace cryptonote return false; } transactions_container::iterator tx_it = m_transactions.find(amount_outs_vec[i].first); - CHECK_AND_ASSERT_MES(tx_it != m_transactions.end(), false, "Wrong transaction id in output indexes: " <second.tx.vout.size(), false, "Wrong index in transaction outputs: " << amount_outs_vec[i].second << ", expected less then " << tx_it->second.tx.vout.size()); if(!vis.handle_output(tx_it->second.tx, tx_it->second.tx.vout[amount_outs_vec[i].second])) diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index 54c2f3a6d..33a2d2986 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -29,10 +29,11 @@ namespace cryptonote return !m_points.empty() && (height <= (--m_points.end())->first); } //--------------------------------------------------------------------------- - bool checkpoints::check_block(uint64_t height, const crypto::hash& h) const + bool checkpoints::check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const { auto it = m_points.find(height); - if(it == m_points.end()) + is_a_checkpoint = it != m_points.end(); + if(!is_a_checkpoint) return true; if(it->second == h) @@ -45,4 +46,25 @@ namespace cryptonote return false; } } + //--------------------------------------------------------------------------- + bool checkpoints::check_block(uint64_t height, const crypto::hash& h) const + { + bool ignored; + return check_block(height, h, ignored); + } + //--------------------------------------------------------------------------- + bool checkpoints::is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const + { + if (0 == block_height) + return false; + + auto it = m_points.upper_bound(blockchain_height); + // Is blockchain_height before the first checkpoint? + if (it == m_points.begin()) + return true; + + --it; + uint64_t checkpoint_height = it->first; + return checkpoint_height < block_height; + } } diff --git a/src/cryptonote_core/checkpoints.h b/src/cryptonote_core/checkpoints.h index 20014b1c8..1bc055d91 100644 --- a/src/cryptonote_core/checkpoints.h +++ b/src/cryptonote_core/checkpoints.h @@ -16,6 +16,9 @@ namespace cryptonote bool add_checkpoint(uint64_t height, const std::string& hash_str); bool is_in_checkpoint_zone(uint64_t height) const; bool check_block(uint64_t height, const crypto::hash& h) const; + bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; + bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const; + private: std::map m_points; }; diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h index 32d15831f..3ecbbf0b6 100644 --- a/src/cryptonote_core/checkpoints_create.h +++ b/src/cryptonote_core/checkpoints_create.h @@ -12,12 +12,9 @@ namespace cryptonote { inline bool create_checkpoints(cryptonote::checkpoints& checkpoints) { - // Checkpointing disabled until we can make the client not fast-sync - // without checking PoW at some point. Otherwise we may be exposed - // to blockchain corruption attacks. Need to investigate this further. - // 8-5-14 - // ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); - // ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); + ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); + ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); + ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); return true; } } diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index a09f25d31..b6bfa09c8 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -502,7 +502,7 @@ namespace cryptonote LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL << "The daemon will start synchronizing with the network. It may take up to several hours." << ENDL << ENDL - << "You can set the level of process detailization by using command \"set_log \", where is either 0 (no details), 1 (current block height synchronized), or 2 (all details)." << ENDL + << "You can set the level of process detailization* through \"set_log \" command*, where is between 0 (no details) and 4 (very verbose)." << ENDL << ENDL << "Use \"help\" command to see the list of available commands." << ENDL << ENDL diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index c298451e8..cde52d5a2 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -115,13 +115,13 @@ namespace cryptonote tx_memory_pool m_mempool; blockchain_storage m_blockchain_storage; i_cryptonote_protocol* m_pprotocol; - critical_section m_incoming_tx_lock; + epee::critical_section m_incoming_tx_lock; //m_miner and m_miner_addres are probably temporary here miner m_miner; account_public_address m_miner_address; std::string m_config_folder; cryptonote_protocol_stub m_protocol_stub; - math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; + epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; friend class tx_validate_inputs; std::atomic m_starter_message_showed; }; diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 2b38d001f..7b7f18844 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -239,8 +239,7 @@ namespace cryptonote crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra) { std::vector tx_extra_fields; - if (!parse_tx_extra(tx_extra, tx_extra_fields)) - return null_pkey; + parse_tx_extra(tx_extra, tx_extra_fields); tx_extra_pub_key pub_key_field; if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field)) diff --git a/src/cryptonote_core/miner.h b/src/cryptonote_core/miner.h index f1e4e5dce..d9ac5a501 100644 --- a/src/cryptonote_core/miner.h +++ b/src/cryptonote_core/miner.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include "cryptonote_basic.h" @@ -66,7 +65,7 @@ namespace cryptonote volatile uint32_t m_stop; - ::critical_section m_template_lock; + epee::critical_section m_template_lock; block m_template; std::atomic m_template_no; std::atomic m_starter_nonce; @@ -75,21 +74,21 @@ namespace cryptonote volatile uint32_t m_thread_index; volatile uint32_t m_threads_total; std::atomic m_pausers_count; - ::critical_section m_miners_count_lock; + epee::critical_section m_miners_count_lock; std::list m_threads; - ::critical_section m_threads_lock; + epee::critical_section m_threads_lock; i_miner_handler* m_phandler; account_public_address m_mine_address; - math_helper::once_a_time_seconds<5> m_update_block_template_interval; - math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; + epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval; + epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; std::vector m_extra_messages; miner_config m_config; std::string m_config_folder_path; std::atomic m_last_hr_merge_time; std::atomic m_hashes; std::atomic m_current_hash_rate; - critical_section m_last_hash_rates_lock; + epee::critical_section m_last_hash_rates_lock; std::list m_last_hash_rates; bool m_do_print_hashrate; bool m_do_mining; diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index 254a6a2ff..37a04a41e 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -135,7 +135,6 @@ namespace cryptonote // varint tag; // varint size; // varint data[]; - //typedef boost::variant tx_extra_field; typedef boost::variant tx_extra_field; } diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 24e5752ad..4c4c6aea1 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -350,18 +350,69 @@ namespace cryptonote //--------------------------------------------------------------------------------- bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee) { + // Warning: This function takes already_generated_ + // coins as an argument and appears to do nothing + // with it. + CRITICAL_REGION_LOCAL(m_transactions_lock); total_size = 0; fee = 0; - size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; // Max block size std::unordered_set k_images; + + // Tx size limit as in wallet2.h + // tx_pool.cpp uses size_t for tx sizes, whereas + // wallet2.h uses uint64_t; just use size_t here + // for now + size_t upper_transaction_size_limit = ((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + + // Calculate size limit based on median too; useful + // for when we actually fix wallet2.h's maximum + // allowable tx size + // + // Can be removed when wallet2.h calculates max + // tx size based on the median too; just use + // upper_transaction_size_limit_median in all cases + size_t upper_transaction_size_limit_median = ((median_size * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + if (upper_transaction_size_limit_median > upper_transaction_size_limit) + upper_transaction_size_limit = upper_transaction_size_limit_median; + BOOST_FOREACH(transactions_container::value_type& tx, m_transactions) { + // Can not exceed maximum block size if (max_total_size < total_size + tx.second.blob_size) continue; + // Check to see if the minimum fee is included; + // exclude tx missing minimum fee + if (tx.second.fee < DEFAULT_FEE) + continue; + + // Skip transactions that are too large + // TODO: Correct upper_transactions_size_limit + // such that it is based on median block size; + // We need to make a similar patch for + // wallet2.h + if (tx.second.blob_size > upper_transaction_size_limit) + continue; + + // If adding this tx will make the block size + // greater than 130% of the median, reject the + // tx; this will keep down largely punitive tx + // from being included + if ( (total_size + tx.second.blob_size) > ((130 * median_size) / 100) ) + continue; + + // If we've exceeded the penalty free size, + // stop including more tx + if (total_size > median_size) + break; + + // Skip transactions that are not ready to be + // included into the blockchain or that are + // missing key images if (!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) continue; diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 3978dfb96..26d273aa7 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -4,8 +4,6 @@ #pragma once #include "include_base_utils.h" -using namespace epee; - #include #include diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 178ec2eb1..80538677c 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -81,7 +81,7 @@ namespace cryptonote template bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context) { - LOG_PRINT_L2("[" << net_utils::print_connection_context_short(context) << "] post " << typeid(t_parametr).name() << " -->"); + LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parametr).name() << " -->"); std::string blob; epee::serialization::store_t_to_binary(arg, blob); return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context); @@ -90,7 +90,7 @@ namespace cryptonote template bool relay_post_notify(typename t_parametr::request& arg, cryptonote_connection_context& exlude_context) { - LOG_PRINT_L2("[" << net_utils::print_connection_context_short(exlude_context) << "] post relay " << typeid(t_parametr).name() << " -->"); + LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(exlude_context) << "] post relay " << typeid(t_parametr).name() << " -->"); std::string arg_buff; epee::serialization::store_t_to_binary(arg, arg_buff); return m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index a0838e690..2584f1097 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -81,7 +81,7 @@ namespace cryptonote m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id) { ss << std::setw(25) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") + - string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) + epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) << std::setw(20) << std::hex << peer_id << std::setw(25) << 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) + ")" << std::setw(25) << get_protocol_state_string(cntxt.m_state) @@ -108,9 +108,12 @@ namespace cryptonote return true; } - LOG_PRINT_CCONTEXT_YELLOW("Sync data returned unknown top block: " << m_core.get_current_blockchain_height() << "->" << hshd.current_height - << "[" << static_cast(hshd.current_height - m_core.get_current_blockchain_height()) << " blocks(" << (hshd.current_height - m_core.get_current_blockchain_height()) /1440 << " days) behind] " << ENDL - << "remote top: " << hshd.top_id << "[" << hshd.current_height << "]" << ", set SYNCHRONIZATION mode", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1)); + int64_t diff = static_cast(hshd.current_height) - static_cast(m_core.get_current_blockchain_height()); + LOG_PRINT_CCONTEXT_YELLOW("Sync data returned unknown top block: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height + << " [" << std::abs(diff) << " blocks (" << diff / (24 * 60 * 60 / DIFFICULTY_TARGET) << " days) " + << (0 <= diff ? std::string("behind") : std::string("ahead")) + << "] " << ENDL << "SYNCHRONIZATION started", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1)); + LOG_PRINT_L1("Remote top block height: " << hshd.current_height << ", id: " << hshd.top_id); context.m_state = cryptonote_connection_context::state_synchronizing; context.m_remote_blockchain_height = hshd.current_height; //let the socket to send response to handshake, but request callback, to let send request data after response @@ -254,7 +257,7 @@ namespace cryptonote if(!parse_and_validate_block_from_blob(block_entry.block, b)) { LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: \r\n" - << string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection"); + << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection"); m_p2p->drop_connection(context); return 1; } @@ -274,14 +277,14 @@ namespace cryptonote auto req_it = context.m_requested_objects.find(get_block_hash(b)); if(req_it == context.m_requested_objects.end()) { - LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block)) << " wasn't requested, dropping connection"); m_p2p->drop_connection(context); return 1; } if(b.tx_hashes.size() != block_entry.txs.size()) { - LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block)) << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection"); m_p2p->drop_connection(context); return 1; @@ -300,7 +303,7 @@ namespace cryptonote { m_core.pause_mine(); - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler( boost::bind(&t_core::resume_mine, &m_core)); BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks) @@ -314,7 +317,7 @@ namespace cryptonote if(tvc.m_verifivation_failed) { LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = " - << string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection"); + << epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection"); m_p2p->drop_connection(context); return 1; } @@ -408,7 +411,7 @@ namespace cryptonote << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height << "\r\nm_needed_objects.size()=" << context.m_needed_objects.size() << "\r\nm_requested_objects.size()=" << context.m_requested_objects.size() - << "\r\non connection [" << net_utils::print_connection_context_short(context)<< "]"); + << "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]"); context.m_state = cryptonote_connection_context::state_normal; LOG_PRINT_CCONTEXT_GREEN(" SYNCHRONIZED OK", LOG_LEVEL_0); @@ -464,7 +467,7 @@ namespace cryptonote if(!m_core.have_block(arg.m_block_ids.front())) { LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: " - << string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); + << epee::string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); m_p2p->drop_connection(context); return 1; } diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 74b671e2a..135ec68f8 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -11,6 +11,7 @@ #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "common/util.h" #include "crypto/hash.h" +#include "version.h" class daemon_cmmands_handler @@ -34,6 +35,7 @@ public: m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_cmmands_handler::show_hr, this, _1), "Start showing hash rate"); m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_cmmands_handler::hide_hr, this, _1), "Stop showing hash rate"); m_cmd_binder.set_handler("save", boost::bind(&daemon_cmmands_handler::save, this, _1), "Save blockchain"); + m_cmd_binder.set_handler("set_log", boost::bind(&daemon_cmmands_handler::set_log, this, _1), "set_log - Change current log detalization level, is a number 0-4"); m_cmd_binder.set_handler("diff", boost::bind(&daemon_cmmands_handler::diff, this, _1), "Show difficulty"); } @@ -55,6 +57,7 @@ private: std::string get_commands_str() { std::stringstream ss; + ss << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL; ss << "Commands: " << ENDL; std::string usage = m_cmd_binder.get_usage(); boost::replace_all(usage, "\n", "\n "); @@ -135,19 +138,34 @@ private: return false; } uint64_t start_index = 0; + uint64_t end_index = 0; uint64_t end_block_parametr = m_srv.get_payload_object().get_core().get_current_blockchain_height(); if(!string_tools::get_xtype_from_string(start_index, args[0])) { std::cout << "wrong starter block index parameter" << ENDL; return false; } - if(args.size() >1 && !string_tools::get_xtype_from_string(end_block_parametr, args[1])) + if(args.size() >1 && !string_tools::get_xtype_from_string(end_index, args[1])) { std::cout << "wrong end block index parameter" << ENDL; return false; } + if (end_index == 0) + { + end_index = end_block_parametr; + } + if (end_index > end_block_parametr) + { + std::cout << "end block index parameter shouldn't be greater than " << end_block_parametr << ENDL; + return false; + } + if (end_index <= start_index) + { + std::cout << "end block index should be greater than starter block index" << ENDL; + return false; + } - m_srv.get_payload_object().get_core().print_blockchain(start_index, end_block_parametr); + m_srv.get_payload_object().get_core().print_blockchain(start_index, end_index); return true; } //-------------------------------------------------------------------------------- @@ -156,6 +174,33 @@ private: m_srv.get_payload_object().get_core().print_blockchain_index(); return true; } + + bool set_log(const std::vector& args) + { + if(args.size() != 1) + { + std::cout << "use: set_log " << ENDL; + return true; + } + + uint16_t l = 0; + if(!string_tools::get_xtype_from_string(l, args[0])) + { + std::cout << "wrong number format, use: set_log " << ENDL; + return true; + } + + if(LOG_LEVEL_4 < l) + { + std::cout << "wrong number range, use: set_log " << ENDL; + return true; + } + + log_space::log_singletone::get_set_log_detalisation_level(true, l); + + return true; + } + //-------------------------------------------------------------------------------- template static bool print_as_json(T& obj) diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 794b97429..5a03b049f 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -24,8 +24,7 @@ #include "p2p_networks.h" #include "math_helper.h" #include "net_node_common.h" - -using namespace epee; +#include "common/command_line.h" PUSH_WARNINGS DISABLE_VS_WARNINGS(4355) @@ -39,7 +38,7 @@ namespace nodetool }; template - class node_server: public levin::levin_commands_handler >, + class node_server: public epee::levin::levin_commands_handler >, public i_p2p_endpoint { struct by_conn_id{}; @@ -126,7 +125,7 @@ namespace nodetool bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); bool handle_command_line(const boost::program_options::variables_map& vm); bool idle_worker(); - bool handle_remote_peerlist(const std::list& peerlist, time_t local_time, const net_utils::connection_context_base& context); + bool handle_remote_peerlist(const std::list& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context); bool get_local_node_data(basic_node_data& node_data); //bool get_local_handshake_data(handshake_data& hshd); @@ -136,7 +135,7 @@ namespace nodetool bool connections_maker(); bool peer_sync_idle_maker(); bool do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context, bool just_take_peerlist = false); - bool do_peer_timed_sync(const net_utils::connection_context_base& context, peerid_type peer_id); + bool do_peer_timed_sync(const epee::net_utils::connection_context_base& context, peerid_type peer_id); 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, bool white = true); @@ -146,12 +145,19 @@ namespace nodetool template bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb); bool make_expected_connections_count(bool white_list, size_t expected_connections); + bool is_priority_node(const net_address& na); + + template + bool connect_to_peerlist(const Container& peers); + + template + bool parse_peers_and_add_to_container(const boost::program_options::variables_map& vm, const command_line::arg_descriptor > & arg, Container& container); //debug functions std::string print_connections_container(); - typedef net_utils::boosted_tcp_server > net_server; + typedef epee::net_utils::boosted_tcp_server > net_server; struct config { @@ -181,9 +187,9 @@ namespace nodetool t_payload_net_handler& m_payload_handler; peerlist_manager m_peerlist; - math_helper::once_a_time_seconds m_peer_handshake_idle_maker_interval; - math_helper::once_a_time_seconds<1> m_connections_maker_interval; - math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval; + epee::math_helper::once_a_time_seconds m_peer_handshake_idle_maker_interval; + epee::math_helper::once_a_time_seconds<1> m_connections_maker_interval; + epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval; std::string m_bind_ip; std::string m_port; @@ -191,6 +197,7 @@ namespace nodetool uint64_t m_last_stat_request_time; #endif std::list m_priority_peers; + std::vector m_exclusive_peers; std::vector m_seed_nodes; std::list m_command_line_peers; uint64_t m_peer_livetime; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 31d3e6597..e45e51b77 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -4,9 +4,10 @@ #pragma once +#include + #include "version.h" #include "string_tools.h" -#include "common/command_line.h" #include "common/util.h" #include "net/net_helper.h" #include "math_helper.h" @@ -31,8 +32,11 @@ namespace nodetool const command_line::arg_descriptor arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"}; const command_line::arg_descriptor > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"}; const command_line::arg_descriptor > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"}; + const command_line::arg_descriptor > arg_p2p_add_exclusive_node = {"add-exclusive-node", "Specify list of peers to connect to only." + " If this option is given the options add-priority-node and seed-node are ignored"}; const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; - const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; } + const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; + } //----------------------------------------------------------------------------------- template @@ -44,6 +48,7 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_allow_local_ip); command_line::add_arg(desc, arg_p2p_add_peer); command_line::add_arg(desc, arg_p2p_add_priority_node); + command_line::add_arg(desc, arg_p2p_add_exclusive_node); command_line::add_arg(desc, arg_p2p_seed_node); command_line::add_arg(desc, arg_p2p_hide_my_port); } //----------------------------------------------------------------------------------- @@ -96,7 +101,7 @@ namespace nodetool template bool node_server::parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr) { - return string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr); + return epee::string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr); } //----------------------------------------------------------------------------------- template @@ -120,30 +125,26 @@ namespace nodetool } } - if (command_line::has_arg(vm, arg_p2p_add_priority_node)) - { - std::vector perrs = command_line::get_arg(vm, arg_p2p_add_priority_node); - for(const std::string& pr_str: perrs) - { - nodetool::net_address na = AUTO_VAL_INIT(na); - bool r = parse_peer_from_string(na, pr_str); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); - m_priority_peers.push_back(na); - } + if (command_line::has_arg(vm,arg_p2p_add_exclusive_node)) + { + if (!parse_peers_and_add_to_container(vm, arg_p2p_add_exclusive_node, m_exclusive_peers)) + return false; + } + else if (command_line::has_arg(vm, arg_p2p_add_priority_node)) + { + if (!parse_peers_and_add_to_container(vm, arg_p2p_add_priority_node, m_priority_peers)) + return false; } if (command_line::has_arg(vm, arg_p2p_seed_node)) { - std::vector seed_perrs = command_line::get_arg(vm, arg_p2p_seed_node); - for(const std::string& pr_str: seed_perrs) - { - nodetool::net_address na = AUTO_VAL_INIT(na); - bool r = parse_peer_from_string(na, pr_str); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << pr_str); - m_seed_nodes.push_back(na); - } + if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes)) + return false; } + if(command_line::has_arg(vm, arg_p2p_hide_my_port)) - m_hide_my_port = true; return true; + m_hide_my_port = true; + + return true; } //----------------------------------------------------------------------------------- namespace @@ -353,23 +354,23 @@ namespace nodetool get_local_node_data(arg.node_data); m_payload_handler.get_payload_sync_data(arg.payload_data); - simple_event ev; + epee::simple_event ev; std::atomic hsh_result(false); - bool r = net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(), + bool r = epee::net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(), [this, &pi, &ev, &hsh_result, &just_take_peerlist](int code, const typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context) { - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.raise();}); + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ev.raise();}); if(code < 0) { - LOG_PRINT_CC_RED(context, "COMMAND_HANDSHAKE invoke failed. (" << code << ", " << levin::get_err_descr(code) << ")", LOG_LEVEL_1); + LOG_PRINT_CC_RED(context, "COMMAND_HANDSHAKE invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")", LOG_LEVEL_1); return; } if(rsp.node_data.network_id != BYTECOIN_NETWORK) { - LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong network! (" << string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection."); + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong network! (" << epee::string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection."); return; } @@ -397,10 +398,10 @@ namespace nodetool hsh_result = false; return; } - LOG_PRINT_CCONTEXT_L0(" COMMAND_HANDSHAKE INVOKED OK"); + LOG_PRINT_CCONTEXT_L1(" COMMAND_HANDSHAKE INVOKED OK"); }else { - LOG_PRINT_CCONTEXT_L0(" COMMAND_HANDSHAKE(AND CLOSE) INVOKED OK"); + LOG_PRINT_CCONTEXT_L1(" COMMAND_HANDSHAKE(AND CLOSE) INVOKED OK"); } }, P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT); @@ -411,7 +412,7 @@ namespace nodetool if(!hsh_result) { - LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed"); + LOG_PRINT_CC_L1(context_, "COMMAND_HANDSHAKE Failed"); m_net_server.get_config_object().close(context_.m_connection_id); } @@ -419,17 +420,17 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::do_peer_timed_sync(const net_utils::connection_context_base& context_, peerid_type peer_id) + bool node_server::do_peer_timed_sync(const epee::net_utils::connection_context_base& context_, peerid_type peer_id) { typename COMMAND_TIMED_SYNC::request arg = AUTO_VAL_INIT(arg); m_payload_handler.get_payload_sync_data(arg.payload_data); - bool r = net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_TIMED_SYNC::ID, arg, m_net_server.get_config_object(), + bool r = epee::net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_TIMED_SYNC::ID, arg, m_net_server.get_config_object(), [this](int code, const typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context) { if(code < 0) { - LOG_PRINT_CC_RED(context, "COMMAND_TIMED_SYNC invoke failed. (" << code << ", " << levin::get_err_descr(code) << ")", LOG_LEVEL_1); + LOG_PRINT_CC_RED(context, "COMMAND_TIMED_SYNC invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")", LOG_LEVEL_1); return; } @@ -502,36 +503,53 @@ namespace nodetool return connected; } - //----------------------------------------------------------------------------------- +#define LOG_PRINT_CC_PRIORITY_NODE(priority, con, msg) \ + do { \ + if (priority) {\ + LOG_PRINT_CC_L0(con, msg); \ + } else {\ + LOG_PRINT_CC_L1(con, msg); \ + } \ + } while(0) + template bool node_server::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white) { - LOG_PRINT_L0("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")..."); + LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":" + << epee::string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " + << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never") + << ")..."); typename net_server::t_connection_context con = AUTO_VAL_INIT(con); - bool res = m_net_server.connect(string_tools::get_ip_string_from_int32(na.ip), - string_tools::num_to_string_fast(na.port), + 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), m_config.m_net_config.connection_timeout, con); + if(!res) { - LOG_PRINT_L0("Connect failed to " - << string_tools::get_ip_string_from_int32(na.ip) - << ":" << string_tools::num_to_string_fast(na.port) + 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) /*<< ", try " << try_count*/); //m_peerlist.set_peer_unreachable(pe); return false; } + peerid_type pi = AUTO_VAL_INIT(pi); res = do_handshake_with_peer(pi, con, just_take_peerlist); + if(!res) { - LOG_PRINT_CC_L0(con, "Failed to HANDSHAKE with peer " - << string_tools::get_ip_string_from_int32(na.ip) - << ":" << string_tools::num_to_string_fast(na.port) + 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) /*<< ", try " << try_count*/); return false; } + if(just_take_peerlist) { m_net_server.get_config_object().close(con.m_connection_id); @@ -549,6 +567,9 @@ namespace nodetool LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK.", LOG_LEVEL_2); return true; } + +#undef LOG_PRINT_CC_PRIORITY_NODE + //----------------------------------------------------------------------------------- template bool node_server::make_new_connection_from_peerlist(bool use_white_list) @@ -582,7 +603,10 @@ namespace nodetool if(is_peer_used(pe)) continue; - LOG_PRINT_L1("Selected peer: " << pe.id << " " << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast(pe.adr.port) << "[white=" << use_white_list << "] last_seen: " << (pe.last_seen ? misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never")); + LOG_PRINT_L1("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) + << ":" << boost::lexical_cast(pe.adr.port) + << "[white=" << use_white_list + << "] last_seen: " << (pe.last_seen ? epee::misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never")); if(!try_to_connect_and_handshake_with_new_peer(pe.adr, false, pe.last_seen, use_white_list)) continue; @@ -595,6 +619,10 @@ namespace nodetool template bool node_server::connections_maker() { + if (!connect_to_peerlist(m_exclusive_peers)) return false; + + if (!m_exclusive_peers.empty()) return true; + if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size()) { size_t try_count = 0; @@ -616,15 +644,7 @@ namespace nodetool } } - for(const net_address& na: m_priority_peers) - { - if(m_net_server.is_stop_signal_sent()) - return false; - - if(is_addr_connected(na)) - continue; - try_to_connect_and_handshake_with_new_peer(na); - } + if (!connect_to_peerlist(m_priority_peers)) return false; size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100; @@ -698,7 +718,7 @@ namespace nodetool bool node_server::peer_sync_idle_maker() { LOG_PRINT_L2("STARTED PEERLIST IDLE HANDSHAKE"); - typedef std::list > local_connects_type; + typedef std::list > local_connects_type; local_connects_type cncts; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { @@ -725,7 +745,7 @@ namespace nodetool { if(be.last_seen > local_time) { - LOG_PRINT_RED_L0("FOUND FUTURE peerlist for entry " << 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); + LOG_PRINT_RED_L0("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); return false; } be.last_seen += delta; @@ -734,7 +754,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::handle_remote_peerlist(const std::list& peerlist, time_t local_time, const net_utils::connection_context_base& context) + bool node_server::handle_remote_peerlist(const std::list& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context) { int64_t delta = 0; std::list peerlist_ = peerlist; @@ -782,7 +802,7 @@ namespace nodetool return false; } crypto::public_key pk = AUTO_VAL_INIT(pk); - string_tools::hex_to_pod(P2P_STAT_TRUSTED_PUB_KEY, pk); + epee::string_tools::hex_to_pod(P2P_STAT_TRUSTED_PUB_KEY, pk); crypto::hash h = tools::get_proof_of_trust_hash(tr); if(!crypto::check_signature(h, pk, tr.sign)) { @@ -903,8 +923,8 @@ namespace nodetool uint32_t actual_ip = context.m_remote_ip; if(!m_peerlist.is_ip_allowed(actual_ip)) return false; - std::string ip = string_tools::get_ip_string_from_int32(actual_ip); - std::string port = string_tools::num_to_string_fast(node_data.my_port); + 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); 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]( const typename net_server::t_connection_context& ping_context, @@ -922,12 +942,12 @@ namespace nodetool std::string port_=port; peerid_type pr_ = pr; auto cb_ = cb;*/ - bool inv_call_res = net_utils::async_invoke_remote_command2(ping_context.m_connection_id, COMMAND_PING::ID, req, m_net_server.get_config_object(), + bool inv_call_res = epee::net_utils::async_invoke_remote_command2(ping_context.m_connection_id, COMMAND_PING::ID, req, m_net_server.get_config_object(), [=](int code, const COMMAND_PING::response& rsp, p2p_connection_context& context) { if(code <= 0) { - LOG_PRINT_CC_L2(ping_context, "Failed to invoke COMMAND_PING to " << ip << ":" << port << "(" << code << ", " << levin::get_err_descr(code) << ")"); + LOG_PRINT_CC_L2(ping_context, "Failed to invoke COMMAND_PING to " << ip << ":" << port << "(" << code << ", " << epee::levin::get_err_descr(code) << ")"); return; } @@ -979,7 +999,7 @@ namespace nodetool if(arg.node_data.network_id != BYTECOIN_NETWORK) { - LOG_PRINT_CCONTEXT_L0("WRONG NETWORK AGENT CONNECTED! id=" << string_tools::get_str_from_guid_a(arg.node_data.network_id)); + LOG_PRINT_CCONTEXT_L0("WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id)); drop_connection(context); return 1; } @@ -1021,7 +1041,7 @@ namespace nodetool time(&pe.last_seen); pe.id = peer_id_l; this->m_peerlist.append_with_peer_white(pe); - LOG_PRINT_CCONTEXT_L2("PING SUCCESS " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l); + LOG_PRINT_CCONTEXT_L2("PING SUCCESS " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l); }); } @@ -1066,9 +1086,9 @@ namespace nodetool std::stringstream ss; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - ss << string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) << ":" << cntxt.m_remote_port + ss << epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) << ":" << cntxt.m_remote_port << " \t\tpeer_id " << cntxt.peer_id - << " \t\tconn_id " << string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT") + << " \t\tconn_id " << epee::string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT") << std::endl; return true; }); @@ -1079,13 +1099,51 @@ namespace nodetool template void node_server::on_connection_new(p2p_connection_context& context) { - LOG_PRINT_L2("["<< net_utils::print_connection_context(context) << "] NEW CONNECTION"); + LOG_PRINT_L2("["<< epee::net_utils::print_connection_context(context) << "] NEW CONNECTION"); } //----------------------------------------------------------------------------------- template void node_server::on_connection_close(p2p_connection_context& context) { - LOG_PRINT_L2("["<< net_utils::print_connection_context(context) << "] CLOSE CONNECTION"); + LOG_PRINT_L2("["<< epee::net_utils::print_connection_context(context) << "] CLOSE CONNECTION"); + } + + template + bool node_server::is_priority_node(const net_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()); + } + + template template + bool node_server::connect_to_peerlist(const Container& peers) + { + for(const net_address& na: peers) + { + if(m_net_server.is_stop_signal_sent()) + return false; + + if(is_addr_connected(na)) + continue; + + try_to_connect_and_handshake_with_new_peer(na); + } + + return true; + } + + template template + bool node_server::parse_peers_and_add_to_container(const boost::program_options::variables_map& vm, const command_line::arg_descriptor > & arg, Container& container) + { + std::vector perrs = command_line::get_arg(vm, arg); + + for(const std::string& pr_str: perrs) + { + nodetool::net_address na = AUTO_VAL_INIT(na); + bool r = parse_peer_from_string(na, pr_str); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); + container.push_back(na); + } + + return true; } - //----------------------------------------------------------------------------------- } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index e4208b0bb..a724246f1 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -413,7 +413,7 @@ namespace cryptonote return false; } res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); - + res.status = CORE_RPC_STATUS_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -441,7 +441,7 @@ namespace cryptonote error_resp.message = "Block not accepted"; return false; } - res.status = "OK"; + res.status = CORE_RPC_STATUS_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 89d3c9885..b7763ffeb 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -2,6 +2,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include + #include "serialization.h" #include "debug_archive.h" #include "crypto/chacha8.h" diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index 2e69ea0a3..7024fdc03 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -10,6 +10,7 @@ #include #include #include +#include template struct is_blob_type { typedef boost::false_type type; }; @@ -79,8 +80,10 @@ inline bool do_serialize(Archive &ar, T &v) if (!r || !ar.stream().good()) return false; \ } while(0); #define FIELDS(f) \ + do { \ bool r = ::do_serialize(ar, f); \ - if (!r || !ar.stream().good()) return false; + if (!r || !ar.stream().good()) return false; \ + } while(0); #define FIELD(f) \ do { \ ar.tag(#f); \ @@ -99,6 +102,7 @@ inline bool do_serialize(Archive &ar, T &v) ar.serialize_varint(f); \ if (!ar.stream().good()) return false; \ } while(0); + namespace serialization { namespace detail { diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 7485f5cb1..dc45d9d74 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -38,7 +38,6 @@ namespace const command_line::arg_descriptor arg_daemon_address = {"daemon-address", "Use daemon instance at :", ""}; const command_line::arg_descriptor arg_daemon_host = {"daemon-host", "Use daemon instance at host instead of localhost", ""}; const command_line::arg_descriptor arg_password = {"password", "Wallet password", "", true}; - const command_line::arg_descriptor arg_exit_after_cmd = {"exit-after-cmd", "Will not enter in the CLI console after command execution. Default: false", ""}; const command_line::arg_descriptor arg_daemon_port = {"daemon-port", "Use daemon instance at port instead of 8081", 0}; const command_line::arg_descriptor arg_log_level = {"set_log", "", 0, true}; @@ -203,7 +202,7 @@ bool simple_wallet::set_log(const std::vector &args) return true; } uint16_t l = 0; - if(!string_tools::get_xtype_from_string(l, args[0])) + if(!epee::string_tools::get_xtype_from_string(l, args[0])) { fail_msg_writer() << "wrong number format, use: set_log "; return true; @@ -230,8 +229,8 @@ bool simple_wallet::ask_wallet_create_if_needed() wallet_path = string_tools::trim(wallet_path); bool keys_file_exists; - bool wallet_file_exitst; - tools::wallet2::wallet_exists(wallet_path, keys_file_exists, wallet_file_exitst); + bool wallet_file_exists; + tools::wallet2::wallet_exists(wallet_path, keys_file_exists, wallet_file_exists); bool r; if(keys_file_exists) @@ -240,7 +239,7 @@ bool simple_wallet::ask_wallet_create_if_needed() r = true; }else { - if(!wallet_file_exitst) + if(!wallet_file_exists) { std::cout << "The wallet doesn't exist, generating new one" << std::endl; m_generate_new = wallet_path; @@ -750,7 +749,7 @@ bool simple_wallet::transfer(const std::vector &args_) } size_t fake_outs_count; - if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0])) + if(!epee::string_tools::get_xtype_from_string(fake_outs_count, local_args[0])) { fail_msg_writer() << "mixin_count should be non-negative integer, got " << local_args[0]; return true; @@ -929,7 +928,6 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_daemon_host); command_line::add_arg(desc_params, arg_daemon_port); command_line::add_arg(desc_params, arg_command); - command_line::add_arg(desc_params, arg_exit_after_cmd); command_line::add_arg(desc_params, arg_log_level); tools::wallet_rpc_server::init_options(desc_params); @@ -1056,20 +1054,20 @@ int main(int argc, char* argv[]) std::vector command = command_line::get_arg(vm, arg_command); if (!command.empty()) + { w.process_command(command); - - tools::signal_handler::install([&w] { w.stop(); - }); - - const std::string& exit_after_command = command_line::get_arg(vm, arg_exit_after_cmd); - - /* Enters in CLI mode only if --exit-after-cmd is not set to true */ - if ( !boost::iequals(exit_after_command,"true") && !boost::iequals(exit_after_command,"yes") ) { - w.run(); + w.deinit(); } + else + { + tools::signal_handler::install([&w] { + w.stop(); + }); + w.run(); - w.deinit(); + w.deinit(); + } } return 0; //CATCH_ENTRY_L0("main", 1); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 3aa0789ae..3dcaaeaa0 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -132,7 +132,7 @@ namespace cryptonote epee::console_handlers_binder m_cmd_binder; std::unique_ptr m_wallet; - net_utils::http::http_simple_client m_http_client; + epee::net_utils::http::http_simple_client m_http_client; refresh_progress_reporter_t m_refresh_progress_reporter; }; } diff --git a/src/version.h.in b/src/version.h.in index 01d2994f8..f171a8e6b 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" -#define PROJECT_VERSION "0.8.8.2" +#define PROJECT_VERSION "0.8.8" #define PROJECT_VERSION_BUILD_NO "1" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")" diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index e8d67eec2..111b76117 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -455,14 +455,14 @@ void wallet2::generate(const std::string& wallet_, const std::string& password) store(); } //---------------------------------------------------------------------------------------------------- -void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exitst) +void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists) { std::string keys_file, wallet_file; do_prepare_file_names(file_path, keys_file, wallet_file); boost::system::error_code ignore; keys_file_exists = boost::filesystem::exists(keys_file, ignore); - wallet_file_exitst = boost::filesystem::exists(wallet_file, ignore); + wallet_file_exists = boost::filesystem::exists(wallet_file, ignore); } //---------------------------------------------------------------------------------------------------- bool wallet2::prepare_file_names(const std::string& file_path) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index edbf31f2d..f90fc4fac 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -102,7 +102,12 @@ namespace tools void store(); cryptonote::account_base& get_account(){return m_account;} - void init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE*2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); + // upper_transaction_size_limit as defined below is set to + // approximately 125% of the fixed minimum allowable penalty + // free block size. TODO: fix this so that it actually takes + // into account the current median block size rather than + // the minimum block size. + void init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = ((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); bool deinit(); void stop() { m_run.store(false, std::memory_order_relaxed); } @@ -144,7 +149,7 @@ namespace tools a & m_payments; } - static void wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exitst); + static void wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists); private: bool store_keys(const std::string& keys_file_name, const std::string& password); @@ -326,7 +331,7 @@ namespace tools req.amounts.push_back(it->amount()); } - bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getrandom_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status); @@ -421,7 +426,7 @@ namespace tools COMMAND_RPC_SEND_RAW_TX::request req; req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx)); COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; - r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); + r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction"); THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction"); THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, tx, daemon_send_resp.status); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index c575f9272..e6f287d74 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -21,15 +21,15 @@ namespace int main(int argc, char* argv[]) { TRY_ENTRY(); - string_tools::set_module_name_and_folder(argv[0]); + epee::string_tools::set_module_name_and_folder(argv[0]); //set up logging options - log_space::get_set_log_detalisation_level(true, LOG_LEVEL_3); - log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); + epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_3); + epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); - log_space::log_singletone::add_logger(LOGGER_FILE, - log_space::log_singletone::get_default_log_file().c_str(), - log_space::log_singletone::get_default_log_folder().c_str()); + epee::log_space::log_singletone::add_logger(LOGGER_FILE, + epee::log_space::log_singletone::get_default_log_file().c_str(), + epee::log_space::log_singletone::get_default_log_folder().c_str()); po::options_description desc_options("Allowed options"); command_line::add_arg(desc_options, command_line::arg_help); diff --git a/tests/performance_tests/cn_slow_hash.h b/tests/performance_tests/cn_slow_hash.h new file mode 100644 index 000000000..ec001326e --- /dev/null +++ b/tests/performance_tests/cn_slow_hash.h @@ -0,0 +1,45 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "crypto/crypto.h" +#include "cryptonote_core/cryptonote_basic.h" + +class test_cn_slow_hash +{ +public: + static const size_t loop_count = 10; + +#pragma pack(push, 1) + struct data_t + { + char data[13]; + }; +#pragma pack(pop) + + static_assert(13 == sizeof(data_t), "Invalid structure size"); + + bool init() + { + if (!epee::string_tools::hex_to_pod("63617665617420656d70746f72", m_data)) + return false; + + if (!epee::string_tools::hex_to_pod("bbec2cacf69866a8e740380fe7b818fc78f8571221742d729d9d02d7f8989b87", m_expected_hash)) + return false; + + return true; + } + + bool test() + { + crypto::hash hash; + crypto::cn_slow_hash(&m_data, sizeof(m_data), hash); + return hash == m_expected_hash; + } + +private: + data_t m_data; + crypto::hash m_expected_hash; +}; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 2ad503b83..72ee2ca6c 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -8,6 +8,7 @@ // tests #include "construct_tx.h" #include "check_ring_signature.h" +#include "cn_slow_hash.h" #include "derive_public_key.h" #include "derive_secret_key.h" #include "generate_key_derivation.h" @@ -56,6 +57,8 @@ int main(int argc, char** argv) TEST_PERFORMANCE0(test_derive_public_key); TEST_PERFORMANCE0(test_derive_secret_key); + TEST_PERFORMANCE0(test_cn_slow_hash); + std::cout << "Tests finished. Elapsed time: " << timer.elapsed_ms() / 1000 << " sec" << std::endl; return 0; diff --git a/tests/unit_tests/checkpoints.cpp b/tests/unit_tests/checkpoints.cpp new file mode 100644 index 000000000..0d7bd4de9 --- /dev/null +++ b/tests/unit_tests/checkpoints.cpp @@ -0,0 +1,140 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include "cryptonote_core/checkpoints.cpp" + +using namespace cryptonote; + + +TEST(checkpoints_is_alternative_block_allowed, handles_empty_checkpoins) +{ + checkpoints cp; + + ASSERT_FALSE(cp.is_alternative_block_allowed(0, 0)); + + ASSERT_TRUE(cp.is_alternative_block_allowed(1, 1)); + ASSERT_TRUE(cp.is_alternative_block_allowed(1, 9)); + ASSERT_TRUE(cp.is_alternative_block_allowed(9, 1)); +} + +TEST(checkpoints_is_alternative_block_allowed, handles_one_checkpoint) +{ + checkpoints cp; + cp.add_checkpoint(5, "0000000000000000000000000000000000000000000000000000000000000000"); + + ASSERT_FALSE(cp.is_alternative_block_allowed(0, 0)); + + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 1)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 4)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 9)); + + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 1)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 4)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 9)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(5, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(5, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(5, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 9)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(6, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(6, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(6, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 9)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(9, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(9, 9)); +} + +TEST(checkpoints_is_alternative_block_allowed, handles_two_and_more_checkpoints) +{ + checkpoints cp; + cp.add_checkpoint(5, "0000000000000000000000000000000000000000000000000000000000000000"); + cp.add_checkpoint(9, "0000000000000000000000000000000000000000000000000000000000000000"); + + ASSERT_FALSE(cp.is_alternative_block_allowed(0, 0)); + + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 1)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 4)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 8)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(1, 11)); + + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 1)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 4)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 8)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(4, 11)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(5, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(5, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(5, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 8)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(5, 11)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(6, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(6, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(6, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 8)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(6, 11)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(8, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(8, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(8, 5)); + ASSERT_TRUE (cp.is_alternative_block_allowed(8, 6)); + ASSERT_TRUE (cp.is_alternative_block_allowed(8, 8)); + ASSERT_TRUE (cp.is_alternative_block_allowed(8, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(8, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(8, 11)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 5)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 6)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 8)); + ASSERT_FALSE(cp.is_alternative_block_allowed(9, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(9, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(9, 11)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(10, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(10, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(10, 5)); + ASSERT_FALSE(cp.is_alternative_block_allowed(10, 6)); + ASSERT_FALSE(cp.is_alternative_block_allowed(10, 8)); + ASSERT_FALSE(cp.is_alternative_block_allowed(10, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(10, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(10, 11)); + + ASSERT_FALSE(cp.is_alternative_block_allowed(11, 1)); + ASSERT_FALSE(cp.is_alternative_block_allowed(11, 4)); + ASSERT_FALSE(cp.is_alternative_block_allowed(11, 5)); + ASSERT_FALSE(cp.is_alternative_block_allowed(11, 6)); + ASSERT_FALSE(cp.is_alternative_block_allowed(11, 8)); + ASSERT_FALSE(cp.is_alternative_block_allowed(11, 9)); + ASSERT_TRUE (cp.is_alternative_block_allowed(11, 10)); + ASSERT_TRUE (cp.is_alternative_block_allowed(11, 11)); +}