From 1fd886730a444acbd5f96705dec93a1808888ff9 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Tue, 11 Dec 2018 07:20:01 +0200 Subject: [PATCH 01/85] Debug info extracted into separate files. --- CMakeLists.txt | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34d70ef5..49d87197 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,44 @@ cmake_minimum_required(VERSION 3.10) +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo) +endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + +if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + message("==> The configuration is ${CMAKE_BUILD_TYPE}. Debug info will be extracted into separate files.") + + function (add_executable _name) + _add_executable(${ARGV}) + + if (TARGET ${_name}) + message("==> ${_name} executable, debug info will be extracted into separate file.") + set(TargetList "${TargetList} ${_name}") + add_custom_command(TARGET ${_name} POST_BUILD + COMMAND objcopy --only-keep-debug "${_name}" "${_name}.debug" + COMMAND strip --strip-debug --strip-unneeded "${_name}" + COMMAND objcopy --add-gnu-debuglink="${_name}.debug" "${_name}" + ) + endif() + endfunction() + + function (add_library _name _type) + _add_library(${ARGV}) + + if (TARGET ${_name} AND ${_type} STREQUAL SHARED) + message("==> ${_name} library, debug info will be extracted into separate file.") + + set(FNAME "lib${_name}.so") + add_custom_command(TARGET ${_name} POST_BUILD + COMMAND objcopy --only-keep-debug "${FNAME}" "${FNAME}.debug" + COMMAND strip --strip-debug --strip-unneeded "${FNAME}" + COMMAND objcopy --add-gnu-debuglink="${FNAME}.debug" "${FNAME}" + WORKING_DIRECTORY ${GRAFTLETS_OUTPUT_DIR} + ) + endif() + endfunction() + +endif(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + project(graft_server) option(OPT_BUILD_TESTS "Build tests." OFF) From 1eec471d0c834f509b8ba069eb2cf2b83fb8e106 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Wed, 12 Dec 2018 03:15:30 +0200 Subject: [PATCH 02/85] Extracting debug info enhanced. --- CMakeLists.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49d87197..78ba2e32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,11 +12,11 @@ if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) if (TARGET ${_name}) message("==> ${_name} executable, debug info will be extracted into separate file.") - set(TargetList "${TargetList} ${_name}") add_custom_command(TARGET ${_name} POST_BUILD - COMMAND objcopy --only-keep-debug "${_name}" "${_name}.debug" - COMMAND strip --strip-debug --strip-unneeded "${_name}" - COMMAND objcopy --add-gnu-debuglink="${_name}.debug" "${_name}" + COMMAND echo "Extract debug info for $" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --only-keep-debug "$" "$.debug" + COMMAND ${CMAKE_COMMAND} -E chdir $ strip --strip-debug --strip-unneeded "$" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --add-gnu-debuglink="$.debug" "$" ) endif() endfunction() @@ -26,13 +26,11 @@ if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) if (TARGET ${_name} AND ${_type} STREQUAL SHARED) message("==> ${_name} library, debug info will be extracted into separate file.") - - set(FNAME "lib${_name}.so") add_custom_command(TARGET ${_name} POST_BUILD - COMMAND objcopy --only-keep-debug "${FNAME}" "${FNAME}.debug" - COMMAND strip --strip-debug --strip-unneeded "${FNAME}" - COMMAND objcopy --add-gnu-debuglink="${FNAME}.debug" "${FNAME}" - WORKING_DIRECTORY ${GRAFTLETS_OUTPUT_DIR} + COMMAND echo "Extract debug info for $" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --only-keep-debug "$" "$.debug" + COMMAND ${CMAKE_COMMAND} -E chdir $ strip --strip-debug --strip-unneeded "$" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --add-gnu-debuglink="$.debug" "$" ) endif() endfunction() From 3ab797ecafb11a0a009353341fc7999757f7c114 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Wed, 12 Dec 2018 18:22:17 +0200 Subject: [PATCH 03/85] GraftServerTest.genericCallback test fixed. --- test/graft_server_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/graft_server_test.cpp b/test/graft_server_test.cpp index 6023bd0e..e841202d 100644 --- a/test/graft_server_test.cpp +++ b/test/graft_server_test.cpp @@ -1256,7 +1256,7 @@ TEST_F(GraftServerTest, genericCallback) case graft::Status::None: { //find webhook endpoint - auto it = std::find_if(input.headers.begin(), input.headers.end(), [](auto& v)->bool { v.first == "X-Callback"; } ); + auto it = std::find_if(input.headers.begin(), input.headers.end(), [](auto& v)->bool { return v.first == "X-Callback"; } ); assert(it != input.headers.end()); std::string path = it->second; //"http://0.0.0.0:port/callback/" From 623aad7050505122951a498251d7c5556e5f17d9 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Thu, 13 Dec 2018 02:18:21 +0200 Subject: [PATCH 04/85] Extracting debug info messages enhanced. --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78ba2e32..17069cb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,8 @@ if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) _add_executable(${ARGV}) if (TARGET ${_name}) - message("==> ${_name} executable, debug info will be extracted into separate file.") add_custom_command(TARGET ${_name} POST_BUILD - COMMAND echo "Extract debug info for $" + COMMAND echo "$: extracting debug info" COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --only-keep-debug "$" "$.debug" COMMAND ${CMAKE_COMMAND} -E chdir $ strip --strip-debug --strip-unneeded "$" COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --add-gnu-debuglink="$.debug" "$" @@ -25,9 +24,8 @@ if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) _add_library(${ARGV}) if (TARGET ${_name} AND ${_type} STREQUAL SHARED) - message("==> ${_name} library, debug info will be extracted into separate file.") add_custom_command(TARGET ${_name} POST_BUILD - COMMAND echo "Extract debug info for $" + COMMAND echo "$: extracting debug info" COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --only-keep-debug "$" "$.debug" COMMAND ${CMAKE_COMMAND} -E chdir $ strip --strip-debug --strip-unneeded "$" COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --add-gnu-debuglink="$.debug" "$" From bfb80b4320933280dfc1e008852d21b7b4743859 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Sun, 10 Feb 2019 03:23:16 +0200 Subject: [PATCH 05/85] Random part added for supernode announce period. --- data/config.ini | 1 + include/lib/graft/handler_api.h | 5 +++-- include/lib/graft/task.h | 19 +++++++++++++------ include/supernode/supernode.h | 1 + src/lib/graft/task.cpp | 27 +++++++++++++++++---------- src/supernode/supernode.cpp | 4 +++- test/sys_info.cpp | 5 +++-- 7 files changed, 41 insertions(+), 21 deletions(-) diff --git a/data/config.ini b/data/config.ini index 948d4978..99ff30ca 100644 --- a/data/config.ini +++ b/data/config.ini @@ -30,6 +30,7 @@ data-dir= stake-wallet-name=stake-wallet testnet=true stake-wallet-refresh-interval-ms=50000 +stake-wallet-refresh-interval-random-factor=0 [ipfilter] ;; path to ipfilter rules file diff --git a/include/lib/graft/handler_api.h b/include/lib/graft/handler_api.h index 6c9b0092..18cee9fe 100644 --- a/include/lib/graft/handler_api.h +++ b/include/lib/graft/handler_api.h @@ -13,8 +13,9 @@ class HandlerAPI public: virtual void sendUpstreamBlocking(Output& output, Input& input, std::string& err) = 0; virtual bool addPeriodicTask(const Router::Handler& h_worker, - std::chrono::milliseconds interval_ms, - std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max()) = 0; + std::chrono::milliseconds interval_ms, + std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max(), + double random_factor = 0) = 0; virtual request::system_info::Counter& runtimeSysInfo() = 0; virtual const ConfigOpts& configOpts() const = 0; }; diff --git a/include/lib/graft/task.h b/include/lib/graft/task.h index 6fc8f1ad..65f438bb 100644 --- a/include/lib/graft/task.h +++ b/include/lib/graft/task.h @@ -153,19 +153,23 @@ class PeriodicTask : public BaseTask PeriodicTask( TaskManager& manager, const Router::Handler3& h3, std::chrono::milliseconds timeout_ms, - std::chrono::milliseconds initial_timeout_ms + std::chrono::milliseconds initial_timeout_ms, + double random_factor = 0 ) : BaseTask(manager, Router::JobParams({Input(), Router::vars_t(), h3})) , m_timeout_ms(timeout_ms), m_initial_timeout_ms(initial_timeout_ms) + , m_random_factor(random_factor) { } - PeriodicTask(TaskManager& manager, const Router::Handler3& h3, std::chrono::milliseconds timeout_ms) - : PeriodicTask(manager, h3, timeout_ms, timeout_ms) + PeriodicTask(TaskManager& manager, const Router::Handler3& h3, + std::chrono::milliseconds timeout_ms, double random_factor = 0) + : PeriodicTask(manager, h3, timeout_ms, timeout_ms, random_factor) { } std::chrono::milliseconds m_timeout_ms; std::chrono::milliseconds m_initial_timeout_ms; + double m_random_factor; bool m_initial_run {true}; public: @@ -199,7 +203,9 @@ class TaskManager : private HandlerAPI void sendUpstream(BaseTaskPtr bt); void addPeriodicTask(const Router::Handler3& h3, - std::chrono::milliseconds interval_ms, std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max()); + std::chrono::milliseconds interval_ms, + std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max(), + double random_factor = 0); ////getters virtual mg_mgr* getMgMgr() = 0; @@ -220,7 +226,8 @@ class TaskManager : private HandlerAPI virtual void sendUpstreamBlocking(Output& output, Input& input, std::string& err) override; virtual bool addPeriodicTask(const Router::Handler& h_worker, std::chrono::milliseconds interval_ms, - std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max()) override; + std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max(), + double random_factor = 0 ) override; virtual request::system_info::Counter& runtimeSysInfo() override; virtual const ConfigOpts& configOpts() const override; @@ -282,7 +289,7 @@ class TaskManager : private HandlerAPI using PromiseItem = UpstreamTask::PromiseItem; using PromiseQueue = tp::MPMCBoundedQueue; - using PeridicTaskItem = std::tuple; + using PeridicTaskItem = std::tuple; using PeriodicTaskQueue = tp::MPMCBoundedQueue; std::unique_ptr m_promiseQueue; diff --git a/include/supernode/supernode.h b/include/supernode/supernode.h index a6c9ec1c..751ae47e 100644 --- a/include/supernode/supernode.h +++ b/include/supernode/supernode.h @@ -13,6 +13,7 @@ class Supernode : public GraftServer std::string data_dir; std::string stake_wallet_name; size_t stake_wallet_refresh_interval_ms; + double stake_wallet_refresh_interval_random_factor; // runtime parameters. // path to watch-only wallets (supernodes) std::string watchonly_wallets_path; diff --git a/src/lib/graft/task.cpp b/src/lib/graft/task.cpp index 5fe8a0ab..30eef7f7 100644 --- a/src/lib/graft/task.cpp +++ b/src/lib/graft/task.cpp @@ -419,17 +419,18 @@ inline size_t TaskManager::next_pow2(size_t val) } bool TaskManager::addPeriodicTask(const Router::Handler& h_worker, - std::chrono::milliseconds interval_ms, - std::chrono::milliseconds initial_interval_ms) + std::chrono::milliseconds interval_ms, + std::chrono::milliseconds initial_interval_ms, + double random_factor) { if(io_thread) {//it is called from pre_action or post_action, and we can call requestAddPeriodicTask directly - addPeriodicTask({nullptr, h_worker, nullptr}, interval_ms, initial_interval_ms); + addPeriodicTask({nullptr, h_worker, nullptr}, interval_ms, initial_interval_ms, random_factor); return true; } else { - PeridicTaskItem item = std::make_tuple(Router::Handler3(nullptr, h_worker, nullptr), interval_ms, initial_interval_ms); + PeridicTaskItem item = std::make_tuple(Router::Handler3(nullptr, h_worker, nullptr), interval_ms, initial_interval_ms, random_factor); bool ok = m_periodicTaskQueue->push( std::move(item) ); if(!ok) return false; notifyJobReady(); @@ -457,7 +458,8 @@ void TaskManager::checkPeriodicTaskIO() Router::Handler3& h3 = std::get<0>(pti); std::chrono::milliseconds& interval_ms = std::get<1>(pti); std::chrono::milliseconds& initial_interval_ms = std::get<2>(pti); - addPeriodicTask(h3, interval_ms, initial_interval_ms); + double& random_factor = std::get<3>(pti); + addPeriodicTask(h3, interval_ms, initial_interval_ms, random_factor); } } @@ -813,11 +815,11 @@ void TaskManager::processOk(BaseTaskPtr bt) } void TaskManager::addPeriodicTask( - const Router::Handler3& h3, std::chrono::milliseconds interval_ms, std::chrono::milliseconds initial_interval_ms) + const Router::Handler3& h3, std::chrono::milliseconds interval_ms, std::chrono::milliseconds initial_interval_ms, double random_factor) { if(initial_interval_ms == std::chrono::milliseconds::max()) initial_interval_ms = interval_ms; - BaseTask* bt = BaseTask::Create(*this, h3, interval_ms, initial_interval_ms).get(); + BaseTask* bt = BaseTask::Create(*this, h3, interval_ms, initial_interval_ms, random_factor).get(); PeriodicTask* pt = dynamic_cast(bt); assert(pt); schedule(pt); @@ -973,9 +975,14 @@ void PeriodicTask::finalize() std::chrono::milliseconds PeriodicTask::getTimeout() { - auto ret = (m_initial_run) ? m_initial_timeout_ms : m_timeout_ms; - m_initial_run = false; - return ret; + if(m_initial_run) + { + m_initial_run = false; + return m_initial_timeout_ms; + } + if(m_random_factor < 0.0001) return m_timeout_ms; + + return std::chrono::milliseconds( int(m_timeout_ms.count() * (1.0 + std::rand()*m_random_factor/RAND_MAX) )); } ClientTask::ClientTask(ConnectionManager* connectionManager, mg_connection *client, Router::JobParams& prms) diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index cb8b60d1..f7d5611e 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -51,6 +51,7 @@ bool Supernode::initConfigOption(int argc, const char** argv, ConfigOpts& config m_configEx.stake_wallet_refresh_interval_ms = server_conf.get("stake-wallet-refresh-interval-ms", consts::DEFAULT_STAKE_WALLET_REFRESH_INTERFAL_MS); m_configEx.testnet = server_conf.get("testnet", false); + m_configEx.stake_wallet_refresh_interval_random_factor = server_conf.get("stake-wallet-refresh-interval-random-factor", 0); return res; } @@ -141,7 +142,8 @@ void Supernode::startSupernodePeriodicTasks() getLooper().addPeriodicTask( graft::Router::Handler3(nullptr, graft::supernode::request::sendAnnounce, nullptr), std::chrono::milliseconds(m_configEx.stake_wallet_refresh_interval_ms), - std::chrono::milliseconds(initial_interval_ms) + std::chrono::milliseconds(initial_interval_ms), + m_configEx.stake_wallet_refresh_interval_random_factor ); } } diff --git a/test/sys_info.cpp b/test/sys_info.cpp index 3b18a41d..845a10bf 100644 --- a/test/sys_info.cpp +++ b/test/sys_info.cpp @@ -151,8 +151,9 @@ class HandlerAPIImpl : public graft::HandlerAPI public: virtual void sendUpstreamBlocking(Output& output, Input& input, std::string& err) override { } virtual bool addPeriodicTask(const Router::Handler& h_worker, - std::chrono::milliseconds interval_ms, - std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max()) override { } + std::chrono::milliseconds interval_ms, + std::chrono::milliseconds initial_interval_ms = std::chrono::milliseconds::max(), + double random_factor = 0) override { } virtual graft::request::system_info::Counter& runtimeSysInfo() override { return m_sic; From 5d39440aa3f05609b78fdfefcc98d29016f3df7f Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Mon, 11 Feb 2019 15:00:34 +0200 Subject: [PATCH 06/85] Random number generation improved. --- include/lib/graft/common/utils.h | 3 +-- src/lib/graft/task.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/lib/graft/common/utils.h b/include/lib/graft/common/utils.h index 5c1e3f25..6fe439cc 100644 --- a/include/lib/graft/common/utils.h +++ b/include/lib/graft/common/utils.h @@ -12,8 +12,7 @@ std::string base64_encode(const std::string &data); template T random_number(T startRange, T endRange) { - std::random_device rd; - std::mt19937 mt(rd()); + static std::mt19937 mt(std::random_device{}()); std::uniform_int_distribution dist(startRange, endRange); return dist(mt); } diff --git a/src/lib/graft/task.cpp b/src/lib/graft/task.cpp index 30eef7f7..6f61f707 100644 --- a/src/lib/graft/task.cpp +++ b/src/lib/graft/task.cpp @@ -6,6 +6,7 @@ #include "lib/graft/handler_api.h" #include "lib/graft/expiring_list.h" #include "lib/graft/sys_info.h" +#include "lib/graft/common/utils.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "supernode.task" @@ -981,8 +982,9 @@ std::chrono::milliseconds PeriodicTask::getTimeout() return m_initial_timeout_ms; } if(m_random_factor < 0.0001) return m_timeout_ms; - - return std::chrono::milliseconds( int(m_timeout_ms.count() * (1.0 + std::rand()*m_random_factor/RAND_MAX) )); + using i_type = decltype(m_timeout_ms.count()); + i_type v = graft::utils::random_number(m_timeout_ms.count(), (i_type)(m_timeout_ms.count()*(1.0 + m_random_factor))); + return std::chrono::milliseconds(v); } ClientTask::ClientTask(ConnectionManager* connectionManager, mg_connection *client, Router::JobParams& prms) From 80f5a335d110aaac9ff41b5ef3e5ace356d6e9ba Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Fri, 25 Jan 2019 17:53:08 +0200 Subject: [PATCH 07/85] Graftlet subsystem linking fixed. --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6c0948f..00dda3b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,6 +321,8 @@ add_executable(supernode ${PROJECT_SOURCE_DIR}/src/supernode/main.cpp ) +set_target_properties(supernode PROPERTIES LINK_FLAGS "-Wl,-E") + target_include_directories(supernode PRIVATE ${GRAFT_INCLUDE_DIRS} ) From 8ac88171e0e7a7a6117a0413bf2c06e31d5385fb Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Thu, 31 Jan 2019 18:33:34 +0200 Subject: [PATCH 08/85] CommonOpts structure added. --- graftlets/TestGraftlet.cpp | 2 +- graftlets/TestGraftlet1.cpp | 2 +- include/lib/graft/GraftletLoader.h | 6 +++++- include/lib/graft/IGraftlet.h | 7 ++++--- include/lib/graft/serveropts.h | 10 ++++++++++ include/supernode/server.h | 1 + include/supernode/supernode.h | 6 +----- include/walletnode/server.h | 8 +------- src/supernode/server.cpp | 29 ++++++++++++++++++++++++++- src/supernode/supernode.cpp | 32 +++++++----------------------- src/walletnode/server.cpp | 15 ++++---------- test/graftlets_test.cpp | 19 +++++++++++------- 12 files changed, 75 insertions(+), 62 deletions(-) diff --git a/graftlets/TestGraftlet.cpp b/graftlets/TestGraftlet.cpp index e2edaf70..afd30fe4 100644 --- a/graftlets/TestGraftlet.cpp +++ b/graftlets/TestGraftlet.cpp @@ -56,7 +56,7 @@ class TestGraftlet: public IGraftlet return graft::Status::Ok; } - virtual void initOnce() + virtual void initOnce(const graft::CommonOpts& opts) override { // REGISTER_ACTION(TestGraftlet, testUndefined); REGISTER_ACTION(TestGraftlet, testInt1); diff --git a/graftlets/TestGraftlet1.cpp b/graftlets/TestGraftlet1.cpp index d15dcd9b..db700bf7 100644 --- a/graftlets/TestGraftlet1.cpp +++ b/graftlets/TestGraftlet1.cpp @@ -56,7 +56,7 @@ class TestGraftlet1: public IGraftlet return graft::Status::Ok; } - virtual void initOnce() + virtual void initOnce(const graft::CommonOpts& opts) override { // REGISTER_ACTION(TestGraftlet1, testUndefined); REGISTER_ACTION(TestGraftlet1, testInt1); diff --git a/include/lib/graft/GraftletLoader.h b/include/lib/graft/GraftletLoader.h index 24d8236d..df41330b 100644 --- a/include/lib/graft/GraftletLoader.h +++ b/include/lib/graft/GraftletLoader.h @@ -106,6 +106,8 @@ class GraftletLoader using Version = int; using GraftletExceptionList = std::vector< std::pair< DllName, std::vector< std::pair >>>; + GraftletLoader(const graft::CommonOpts& opts) : m_opts(opts) { } + static Version getFwVersion() { return m_fwVersion; } static void setFwVersion(Version fwVersion) { m_fwVersion = fwVersion; } @@ -188,7 +190,7 @@ class GraftletLoader GraftletRegistry* gr = it1->second; std::shared_ptr concreteGraftlet = gr->resolveGraftlet(); if(!concreteGraftlet.get()) throw std::runtime_error("Cannot resolve dll name:" + dllName + " type:" + typeid(BaseT).name()); - concreteGraftlet->init(); + concreteGraftlet->init(m_opts); ClsName name = concreteGraftlet->getClsName(); std::any any(concreteGraftlet); @@ -258,6 +260,8 @@ class GraftletLoader static Version m_fwVersion; static ExceptionMap m_exceptionMap; + const graft::CommonOpts& m_opts; + //we can use functions in a dll until we release object of boost::dll::shared_library //dll name -> (lib, version, path) std::map> m_name2lib; diff --git a/include/lib/graft/IGraftlet.h b/include/lib/graft/IGraftlet.h index efadb8b0..3724b4ff 100644 --- a/include/lib/graft/IGraftlet.h +++ b/include/lib/graft/IGraftlet.h @@ -12,6 +12,7 @@ #include #include #include "lib/graft/router.h" +#include "lib/graft/serveropts.h" #define REGISTER_ACTION(T, f) \ register_handler_memf(#f, this, &T::f) @@ -33,11 +34,11 @@ class IGraftlet IGraftlet(const IGraftlet&) = delete; IGraftlet& operator = (const IGraftlet&) = delete; - void init() + void init(const graft::CommonOpts& opts) { if(m_inited) return; m_inited = true; - initOnce(); + initOnce(opts); } const ClsName& getClsName() const { return m_clsName; } @@ -130,7 +131,7 @@ class IGraftlet } protected: IGraftlet(const ClsName& name = ClsName() ) : m_clsName(name) { } - virtual void initOnce() = 0; + virtual void initOnce(const graft::CommonOpts& opts) = 0; private: using TypeIndex2any = std::map >; using Map = std::map; diff --git a/include/lib/graft/serveropts.h b/include/lib/graft/serveropts.h index 490d49c9..312886df 100644 --- a/include/lib/graft/serveropts.h +++ b/include/lib/graft/serveropts.h @@ -6,6 +6,15 @@ namespace graft { +struct CommonOpts +{ + // testnet flag + bool testnet; + // data directory - base directory where supernode stake wallet and other supernodes wallets are located + std::string data_dir; + std::string wallet_public_address; +}; + struct IPFilterOpts { int requests_per_sec = 0; @@ -30,6 +39,7 @@ struct ConfigOpts std::vector graftlet_dirs; int lru_timeout_ms; IPFilterOpts ipfilter; + CommonOpts common; void check_asserts() const { diff --git a/include/supernode/server.h b/include/supernode/server.h index 11e4880a..d9594201 100644 --- a/include/supernode/server.h +++ b/include/supernode/server.h @@ -49,6 +49,7 @@ class GraftServer private: void initLog(int log_level); void initGlobalContext(); + void prepareDataDir(ConfigOpts& configOpts); void addGenericCallbackRoute(); void serve(); static void initSignals(); diff --git a/include/supernode/supernode.h b/include/supernode/supernode.h index 64c038ca..a99af49b 100644 --- a/include/supernode/supernode.h +++ b/include/supernode/supernode.h @@ -9,19 +9,15 @@ class Supernode : public GraftServer { struct ConfigOptsEx : public ConfigOpts { - // data directory - base directory where supernode stake wallet and other supernodes wallets are located - std::string data_dir; std::string stake_wallet_name; size_t stake_wallet_refresh_interval_ms; double stake_wallet_refresh_interval_random_factor; // runtime parameters. // path to watch-only wallets (supernodes) std::string watchonly_wallets_path; - // testnet flag - bool testnet; }; - void prepareDataDir(); + void prepareSupernode(); void startSupernodePeriodicTasks(); void setHttpRouters(ConnectionManager& httpcm); void setCoapRouters(ConnectionManager& coapcm); diff --git a/include/walletnode/server.h b/include/walletnode/server.h index 85030825..e4adad44 100644 --- a/include/walletnode/server.h +++ b/include/walletnode/server.h @@ -25,19 +25,13 @@ class WalletServer: public GraftServer virtual void initRouters() override; private: - struct ConfigOptsEx : public ConfigOpts - { - // testnet flag - bool testnet; - }; - void initWalletManager(); void startPeriodicTasks(); void setHttpRouters(ConnectionManager& httpcm); void registerWalletRequests(ConnectionManager& httpcm); void flushWalletDiskCaches(); - ConfigOptsEx m_configEx; + ConfigOpts m_configOpts; std::unique_ptr m_walletManager; }; diff --git a/src/supernode/server.cpp b/src/supernode/server.cpp index 053999af..d85bf88a 100644 --- a/src/supernode/server.cpp +++ b/src/supernode/server.cpp @@ -13,6 +13,18 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "supernode.server" +namespace consts { + static const char * DATA_PATH = "supernode/data"; +} + +namespace tools { + // TODO: make it crossplatform + std::string getHomeDir() + { + return std::string(getenv("HOME")); + } +} + namespace graft { static std::function int_handler, term_handler, hup_handler; @@ -66,7 +78,7 @@ void GraftServer::getThreadPoolInfo(uint64_t& activeWorkers, uint64_t& expelledW void GraftServer::initGraftlets() { if(m_graftletLoader) return; - m_graftletLoader = std::make_unique(); + m_graftletLoader = std::make_unique(getCopts().common); LOG_PRINT_L1("Searching graftlets"); for(auto& it : getCopts().graftlet_dirs) { @@ -507,6 +519,9 @@ bool GraftServer::initConfigOption(int argc, const char** argv, ConfigOpts& conf configOpts.workers_expelling_interval_ms = server_conf.get("workers-expelling-interval-ms", 1000); configOpts.upstream_request_timeout = server_conf.get("upstream-request-timeout"); configOpts.lru_timeout_ms = server_conf.get("lru-timeout-ms"); + configOpts.common.data_dir = server_conf.get("data-dir"); + configOpts.common.wallet_public_address = server_conf.get("wallet-public-address", ""); + configOpts.common.testnet = server_conf.get("testnet", false); //ipfilter auto opt_ipfilter = config.get_child_optional("ipfilter"); @@ -557,9 +572,21 @@ bool GraftServer::initConfigOption(int argc, const char** argv, ConfigOpts& conf graft::OutHttp::uri_substitutions.emplace(std::move(name), std::make_tuple(std::move(uri), cnt, keepAlive, timeout)); }); + prepareDataDir(configOpts); + return true; } +void GraftServer::prepareDataDir(ConfigOpts& configOpts) +{ + if (configOpts.common.data_dir.empty()) { + boost::filesystem::path p = boost::filesystem::absolute(tools::getHomeDir()); + p /= ".graft/"; + p /= consts::DATA_PATH; + configOpts.common.data_dir = p.string(); + } +} + void GraftServer::initRouters() { diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index 4da8f793..da82f25a 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -14,20 +14,11 @@ #define MONERO_DEFAULT_LOG_CATEGORY "supernode.supernode" namespace consts { - static const char * DATA_PATH = "supernode/data"; static const char * STAKE_WALLET_PATH = "stake-wallet"; static const char * WATCHONLY_WALLET_PATH = "stake-wallet"; static const size_t DEFAULT_STAKE_WALLET_REFRESH_INTERFAL_MS = 5 * 1000; } -namespace tools { - // TODO: make it crossplatform - std::string getHomeDir() - { - return std::string(getenv("HOME")); - } -} - namespace graft { namespace snd @@ -46,26 +37,17 @@ bool Supernode::initConfigOption(int argc, const char** argv, ConfigOpts& config boost::property_tree::ini_parser::read_ini(m_configEx.config_filename, config); const boost::property_tree::ptree& server_conf = config.get_child("server"); - m_configEx.data_dir = server_conf.get("data-dir"); m_configEx.stake_wallet_name = server_conf.get("stake-wallet-name", "stake-wallet"); m_configEx.stake_wallet_refresh_interval_ms = server_conf.get("stake-wallet-refresh-interval-ms", consts::DEFAULT_STAKE_WALLET_REFRESH_INTERFAL_MS); - m_configEx.testnet = server_conf.get("testnet", false); m_configEx.stake_wallet_refresh_interval_random_factor = server_conf.get("stake-wallet-refresh-interval-random-factor", 0); return res; } -void Supernode::prepareDataDir() +void Supernode::prepareSupernode() { - if (m_configEx.data_dir.empty()) { - boost::filesystem::path p = boost::filesystem::absolute(tools::getHomeDir()); - p /= ".graft/"; - p /= consts::DATA_PATH; - m_configEx.data_dir = p.string(); - } - // create data directory if not exists - boost::filesystem::path data_path(m_configEx.data_dir); + boost::filesystem::path data_path(m_configEx.common.data_dir); boost::filesystem::path stake_wallet_path = data_path / "stake-wallet"; boost::filesystem::path watchonly_wallets_path = data_path / "watch-only-wallets"; @@ -96,22 +78,21 @@ void Supernode::prepareDataDir() (stake_wallet_path / m_configEx.stake_wallet_name).string(), "", // TODO m_configEx.cryptonode_rpc_address, - m_configEx.testnet + m_configEx.common.testnet ); supernode->setNetworkAddress(m_configEx.http_address + "/dapi/v2.0"); // create fullsupernode list instance and put it into global context graft::FullSupernodeListPtr fsl = boost::make_shared( - m_configEx.cryptonode_rpc_address, m_configEx.testnet); - + m_configEx.cryptonode_rpc_address, m_configEx.common.testnet); fsl->add(supernode); //put fsl into global context Context ctx(getLooper().getGcm()); ctx.global["supernode"] = supernode; ctx.global[CONTEXT_KEY_FULLSUPERNODELIST] = fsl; - ctx.global["testnet"] = m_configEx.testnet; + ctx.global["testnet"] = m_configEx.common.testnet; ctx.global["watchonly_wallets_path"] = m_configEx.watchonly_wallets_path; ctx.global["cryptonode_rpc_address"] = m_configEx.cryptonode_rpc_address; } @@ -120,7 +101,8 @@ void Supernode::initMisc(ConfigOpts& configOpts) { ConfigOptsEx& coptsex = static_cast(configOpts); assert(&m_configEx == &coptsex); - prepareDataDir(); + + prepareSupernode(); startSupernodePeriodicTasks(); std::chrono::milliseconds duration( 5000 ); diff --git a/src/walletnode/server.cpp b/src/walletnode/server.cpp index 2dee4575..771b9e2b 100644 --- a/src/walletnode/server.cpp +++ b/src/walletnode/server.cpp @@ -44,8 +44,8 @@ void WalletServer::initMisc(ConfigOpts& configOpts) { Context ctx(getLooper().getGcm()); - ctx.global["testnet"] = m_configEx.testnet; - ctx.global["cryptonode_rpc_address"] = m_configEx.cryptonode_rpc_address; + ctx.global["testnet"] = m_configOpts.common.testnet; + ctx.global["cryptonode_rpc_address"] = m_configOpts.cryptonode_rpc_address; initWalletManager(); @@ -56,7 +56,7 @@ bool WalletServer::run(int argc, const char** argv) { for(;;) { - if(!init(argc, argv, m_configEx)) + if(!init(argc, argv, m_configOpts)) return false; argc = 1; @@ -73,13 +73,6 @@ bool WalletServer::initConfigOption(int argc, const char** argv, ConfigOpts& con if (!GraftServer::initConfigOption(argc, argv, configOpts)) return false; - boost::property_tree::ptree config; - boost::property_tree::ini_parser::read_ini(m_configEx.config_filename, config); - - const boost::property_tree::ptree& server_conf = config.get_child("server"); - - m_configEx.testnet = server_conf.get("testnet", false); - return true; } @@ -87,7 +80,7 @@ void WalletServer::initWalletManager() { assert(!m_walletManager); - m_walletManager = std::make_unique(getLooper(), m_configEx.testnet); + m_walletManager = std::make_unique(getLooper(), m_configOpts.common.testnet); } void WalletServer::initRouters() diff --git a/test/graftlets_test.cpp b/test/graftlets_test.cpp index fe8d11dc..fb16583e 100644 --- a/test/graftlets_test.cpp +++ b/test/graftlets_test.cpp @@ -176,7 +176,8 @@ TEST(DependencyGraph, dependencies) TEST(Graftlets, calls) { - graftlet::GraftletLoader loader; + graft::CommonOpts opts; + graftlet::GraftletLoader loader(opts); loader.findGraftletsInDirectory("./", "so"); loader.findGraftletsInDirectory("./graftlets", "so"); @@ -259,25 +260,27 @@ TEST(Graftlets, calls) TEST(Graftlets, exceptionList) { + graft::CommonOpts opts; + #define VER(a,b) GRAFTLET_MKVER(a,b) using GL = graftlet::GraftletLoader; { GL::setGraftletsExceptionList({}); - GL loader; + GL loader(opts); loader.findGraftletsInDirectory("./graftlets", "so"); IGraftlet::EndpointsVec endpoints = loader.getEndpoints(); EXPECT_EQ(endpoints.size(), 4); } { GL::setGraftletsExceptionList({ {"myGraftlet", {{VER(4,2), VER(5,1)}, {VER(1,0), VER(1,0)}} } }); - GL loader; + GL loader(opts); loader.findGraftletsInDirectory("./graftlets", "so"); IGraftlet::EndpointsVec endpoints = loader.getEndpoints(); EXPECT_EQ(endpoints.size(), 4); } { GL::setGraftletsExceptionList({ {"myGraftlet1", {{VER(4,2), VER(5,1)}, {VER(1,0), VER(1,0)}} } }); - GL loader; + GL loader(opts); loader.findGraftletsInDirectory("./graftlets", "so"); IGraftlet::EndpointsVec endpoints = loader.getEndpoints(); EXPECT_EQ(endpoints.size(), 2); @@ -286,7 +289,7 @@ TEST(Graftlets, exceptionList) GL::setGraftletsExceptionList({ {"myGraftlet", {{VER(4,2), VER(5,1)}, {VER(1,0), VER(1,1)}} }, {"myGraftlet1", {{VER(4,2), VER(5,1)}, {VER(1,0), VER(1,0)}} } }); - GL loader; + GL loader(opts); loader.findGraftletsInDirectory("./graftlets", "so"); IGraftlet::EndpointsVec endpoints = loader.getEndpoints(); EXPECT_EQ(endpoints.size(), 0); @@ -299,13 +302,15 @@ TEST(Graftlets, exceptionList) TEST(Graftlets, checkFwVersion) { + graft::CommonOpts opts; + #define VER(a,b) GRAFTLET_MKVER(a,b) using Version = graftlet::GraftletLoader::Version; Version fwVersion = graftlet::GraftletLoader::getFwVersion(); Version save_ver = fwVersion; { - graftlet::GraftletLoader loader; + graftlet::GraftletLoader loader(opts); loader.findGraftletsInDirectory("./graftlets", "so"); IGraftlet::EndpointsVec endpoints = loader.getEndpoints(); EXPECT_EQ(endpoints.size(), 4); @@ -313,7 +318,7 @@ TEST(Graftlets, checkFwVersion) { graftlet::GraftletLoader::setFwVersion( VER(0,5) ); - graftlet::GraftletLoader loader; + graftlet::GraftletLoader loader(opts); loader.findGraftletsInDirectory("./graftlets", "so"); IGraftlet::EndpointsVec endpoints = loader.getEndpoints(); EXPECT_EQ(endpoints.size(), 2); From c8a3ce40610098c9f693d429e3277db99d8772d3 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Thu, 31 Jan 2019 18:44:06 +0200 Subject: [PATCH 09/85] Graftlet WalletAddress for supernode added. --- data/config.ini | 3 +- graftlets/CMakeLists.txt | 7 ++ graftlets/WalletAddress.cpp | 180 ++++++++++++++++++++++++++++++++++++ graftlets/WalletAddress.h | 50 ++++++++++ 4 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 graftlets/WalletAddress.cpp create mode 100644 graftlets/WalletAddress.h diff --git a/data/config.ini b/data/config.ini index 99ff30ca..89947ec6 100644 --- a/data/config.ini +++ b/data/config.ini @@ -31,6 +31,7 @@ stake-wallet-name=stake-wallet testnet=true stake-wallet-refresh-interval-ms=50000 stake-wallet-refresh-interval-random-factor=0 +wallet-public-address= [ipfilter] ;; path to ipfilter rules file @@ -56,4 +57,4 @@ walletnode=http://127.0.0.1:28694 [graftlets] ;;dirs parameter, a list of directories to search graftlets separated by colons. If a directory is set relative it will be interpreted both relative to the current directory and relative to the executable location. By default, 'graftlets' directory will be used relative to the executable location. ;;e.g. dirs=/var/opt/graftlets:graftlets -dirs=graftlets:/var/opt +dirs=graftlets:graftlets/supernode:/var/opt diff --git a/graftlets/CMakeLists.txt b/graftlets/CMakeLists.txt index 91f76f85..c9ef75dd 100644 --- a/graftlets/CMakeLists.txt +++ b/graftlets/CMakeLists.txt @@ -35,5 +35,12 @@ if (OPT_BUILD_TESTS) add_library(graftlet_plugin1 SHARED TestGraftlet1.cpp ) + + add_library(graftlet_walletAddress SHARED + WalletAddress.cpp + ) + set_target_properties(graftlet_walletAddress PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/supernode + ) endif() diff --git a/graftlets/WalletAddress.cpp b/graftlets/WalletAddress.cpp new file mode 100644 index 00000000..a8e80986 --- /dev/null +++ b/graftlets/WalletAddress.cpp @@ -0,0 +1,180 @@ +// Copyright (c) 2018, The Graft Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#define __GRAFTLET__ +#include "lib/graft/GraftletRegistry.h" +#include "lib/graft/IGraftlet.h" + +#include "WalletAddress.h" +#include "supernode/requestdefines.h" +#include "lib/graft/graft_exception.h" +#include "cryptonote_basic/cryptonote_basic_impl.h" +#include "cryptonote_protocol/blobdatatype.h" +#include "file_io_utils.h" + +#include + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "graftlet.WalletAddress" + +class WalletAddressGraftlet: public IGraftlet +{ +public: + WalletAddressGraftlet(const char* name) : IGraftlet(name) { } + + graft::Status getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output); + std::string prepareWalletKey(const graft::CommonOpts& opts); + + virtual void initOnce(const graft::CommonOpts& opts) override + { + m_testnet = opts.testnet; + m_wallet_public_address = opts.wallet_public_address; + m_id_key = prepareWalletKey(opts); + + REGISTER_ENDPOINT("/dapi/v2.0/cryptonode/getwalletaddress", METHOD_GET | METHOD_POST, WalletAddressGraftlet, getWalletAddressHandler); + } +private: + bool m_testnet; + std::string m_wallet_public_address; + std::string m_id_key; +}; + +GRAFTLET_EXPORTS_BEGIN("wallerAddress", GRAFTLET_MKVER(1,1)); +GRAFTLET_PLUGIN(WalletAddressGraftlet, IGraftlet, "wallerAddressGL"); +GRAFTLET_EXPORTS_END + +GRAFTLET_PLUGIN_DEFAULT_CHECK_FW_VERSION(GRAFTLET_MKVER(0,3)) + +graft::Status WalletAddressGraftlet::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) +{ + using namespace graft::supernode::request; + + LOG_PRINT_L2(__FUNCTION__); + assert(ctx.local.getLastStatus() == graft::Status::None); + if(m_wallet_public_address.empty()) + { + GetWalletAddressErrorResponse res; + res.testnet = m_testnet; + output.load(res); + return graft::Status::Ok; + } + GetWalletAddressResponse res; + res.testnet = m_testnet; + res.wallet_public_address = m_wallet_public_address; + res.id_key = m_id_key; + output.load(res); + return graft::Status::Ok; +} + +std::string WalletAddressGraftlet::prepareWalletKey(const graft::CommonOpts& opts) +{ + if(opts.wallet_public_address.empty()) return std::string(); + + boost::filesystem::path data_path(opts.data_dir); + + cryptonote::account_public_address acc = AUTO_VAL_INIT(acc); + if(!cryptonote::get_account_address_from_str(acc, opts.testnet, opts.wallet_public_address)) + { + std::ostringstream oss; + oss << "invalid wallet-public-address '" << opts.wallet_public_address << "'"; + throw graft::exit_error(oss.str()); + } + + crypto::public_key W; + boost::filesystem::path wallet_keys_file = data_path / "wallet.keys"; + if (!boost::filesystem::exists(wallet_keys_file)) + { + LOG_PRINT_L0("file '") << wallet_keys_file << "' not found. Generating the keys"; + crypto::secret_key w; + crypto::generate_keys(W, w); + //save secret key + boost::filesystem::path wallet_keys_file_tmp = wallet_keys_file; + wallet_keys_file_tmp += ".tmp"; + std::string w_str = epee::string_tools::pod_to_hex(w); + bool r = epee::file_io_utils::save_string_to_file(wallet_keys_file_tmp.string(), w_str); + if(!r) + { + std::ostringstream oss; + oss << "Cannot write to file '" << wallet_keys_file_tmp << "'"; + throw graft::exit_error(oss.str()); + } + boost::system::error_code errcode; + boost::filesystem::rename(wallet_keys_file_tmp, wallet_keys_file, errcode); + assert(!errcode); + } + else + { + LOG_PRINT_L1(" Reading wallet keys file '") << wallet_keys_file << "'"; + std::string w_str; + bool r = epee::file_io_utils::load_file_to_string(wallet_keys_file.string(), w_str); + if(!r) + { + std::ostringstream oss; + oss << "Cannot read file '" << wallet_keys_file << "'"; + throw graft::exit_error(oss.str()); + } + + crypto::secret_key w; + cryptonote::blobdata w_data; + bool ok = epee::string_tools::parse_hexstr_to_binbuff(w_str, w_data) || w_data.size() != sizeof(crypto::secret_key); + if(ok) + { + w = *reinterpret_cast(w_data.data()); + ok = crypto::secret_key_to_public_key(w,W); + } + if(!ok) + { + std::ostringstream oss; + oss << "Corrupted data in the file '" << wallet_keys_file << "'"; + throw graft::exit_error(oss.str()); + } + } + + return epee::string_tools::pod_to_hex(W); +} + +namespace +{ + +struct Informer +{ + Informer() + { + LOG_PRINT_L2("graftlet " << getGraftletName() << " loading"); + } + ~Informer() + { + LOG_PRINT_L2("graftlet " << getGraftletName() << " unloading"); + } +}; + +Informer informer; + +} //namespace + + diff --git a/graftlets/WalletAddress.h b/graftlets/WalletAddress.h new file mode 100644 index 00000000..f58fdf58 --- /dev/null +++ b/graftlets/WalletAddress.h @@ -0,0 +1,50 @@ +// Copyright (c) 2018, The Graft Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "lib/graft/router.h" +#include "lib/graft/jsonrpc.h" + +namespace graft::supernode::request { + +GRAFT_DEFINE_IO_STRUCT_INITED(GetWalletAddressResponse, + (bool, testnet, false), + (std::string, wallet_public_address, ""), + (std::string, id_key, "") + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(GetWalletAddressErrorResponse, + (bool, testnet, false), + (std::string, error, "The wallet public address is not set") + ); + +void registerGetWalletAddressRequest(graft::Router& router); + +} + From a6a1ae896070d792884e5984751f78f274dc864b Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Fri, 1 Feb 2019 19:50:20 +0200 Subject: [PATCH 10/85] Signature added into GetWalletAddressResponse. --- graftlets/WalletAddress.cpp | 121 +++++++++++++++++++++++++++--------- graftlets/WalletAddress.h | 8 +-- 2 files changed, 93 insertions(+), 36 deletions(-) diff --git a/graftlets/WalletAddress.cpp b/graftlets/WalletAddress.cpp index a8e80986..b17d0d80 100644 --- a/graftlets/WalletAddress.cpp +++ b/graftlets/WalletAddress.cpp @@ -47,21 +47,21 @@ class WalletAddressGraftlet: public IGraftlet public: WalletAddressGraftlet(const char* name) : IGraftlet(name) { } - graft::Status getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output); - std::string prepareWalletKey(const graft::CommonOpts& opts); - virtual void initOnce(const graft::CommonOpts& opts) override { - m_testnet = opts.testnet; - m_wallet_public_address = opts.wallet_public_address; - m_id_key = prepareWalletKey(opts); + makeGetWalletAddressResponse(opts); REGISTER_ENDPOINT("/dapi/v2.0/cryptonode/getwalletaddress", METHOD_GET | METHOD_POST, WalletAddressGraftlet, getWalletAddressHandler); } private: - bool m_testnet; - std::string m_wallet_public_address; - std::string m_id_key; + graft::Status getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output); + void makeGetWalletAddressResponse(const graft::CommonOpts& opts); + void checkWalletPublicAddress(const graft::CommonOpts& opts); + void prepareIdKeys(const graft::CommonOpts& opts, crypto::public_key& W, crypto::secret_key& w); + bool verifySignature(); + + graft::supernode::request::GetWalletAddressResponse m_response; + graft::supernode::request::GetWalletAddressErrorResponse m_errorResponse; }; GRAFTLET_EXPORTS_BEGIN("wallerAddress", GRAFTLET_MKVER(1,1)); @@ -70,33 +70,90 @@ GRAFTLET_EXPORTS_END GRAFTLET_PLUGIN_DEFAULT_CHECK_FW_VERSION(GRAFTLET_MKVER(0,3)) -graft::Status WalletAddressGraftlet::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) +namespace +{ + +template +bool parse_hexstr_to_pod(const std::string& s, POD& pod) { - using namespace graft::supernode::request; + cryptonote::blobdata data; + bool ok = epee::string_tools::parse_hexstr_to_binbuff(s, data) + && data.size() == sizeof(pod); + if(!ok) return false; + pod = *reinterpret_cast(data.data()); +} +} //namespace + +graft::Status WalletAddressGraftlet::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) +{ LOG_PRINT_L2(__FUNCTION__); assert(ctx.local.getLastStatus() == graft::Status::None); - if(m_wallet_public_address.empty()) + if(m_response.wallet_public_address.empty()) { - GetWalletAddressErrorResponse res; - res.testnet = m_testnet; - output.load(res); + output.load(m_errorResponse); return graft::Status::Ok; } - GetWalletAddressResponse res; - res.testnet = m_testnet; - res.wallet_public_address = m_wallet_public_address; - res.id_key = m_id_key; - output.load(res); + output.load(m_response); return graft::Status::Ok; } -std::string WalletAddressGraftlet::prepareWalletKey(const graft::CommonOpts& opts) +/*! + * \brief makeGetWalletAddressResponse - fills and signs m_response + */ +void WalletAddressGraftlet::makeGetWalletAddressResponse(const graft::CommonOpts& opts) { - if(opts.wallet_public_address.empty()) return std::string(); + m_errorResponse.testnet = opts.testnet; - boost::filesystem::path data_path(opts.data_dir); + if(opts.wallet_public_address.empty()) return; + checkWalletPublicAddress(opts); + + crypto::public_key W; + crypto::secret_key w; + prepareIdKeys(opts, W, w); + + m_response.testnet = opts.testnet; + m_response.wallet_public_address = opts.wallet_public_address; + m_response.id_key = epee::string_tools::pod_to_hex(W); + + crypto::signature sign; + {//sign + std::string data = m_response.wallet_public_address + ":" + m_response.id_key; + crypto::hash hash; + crypto::cn_fast_hash(data.data(), data.size(), hash); + crypto::generate_signature(hash, W, w, sign); + } + m_response.signature = epee::string_tools::pod_to_hex(sign); + + assert(verifySignature()); +} + +/*! + * \brief verifySignature - only for testing here, the code can be used on the other side + */ +bool WalletAddressGraftlet::verifySignature() +{ + crypto::public_key W; + bool ok = parse_hexstr_to_pod(m_response.id_key, W); + assert(ok); + + crypto::signature sign; + bool ok1 = parse_hexstr_to_pod(m_response.signature, sign); + assert(ok1); + + std::string data = m_response.wallet_public_address + ":" + m_response.id_key; + crypto::hash hash; + crypto::cn_fast_hash(data.data(), data.size(), hash); + return crypto::check_signature(hash, W, sign); +} + +/*! + * \brief checkWalletPublicAddress - checks that opts.wallet_public_address is valid + * on error throws graft::exit_error exception + */ +void WalletAddressGraftlet::checkWalletPublicAddress(const graft::CommonOpts& opts) +{ cryptonote::account_public_address acc = AUTO_VAL_INIT(acc); if(!cryptonote::get_account_address_from_str(acc, opts.testnet, opts.wallet_public_address)) { @@ -104,13 +161,20 @@ std::string WalletAddressGraftlet::prepareWalletKey(const graft::CommonOpts& opt oss << "invalid wallet-public-address '" << opts.wallet_public_address << "'"; throw graft::exit_error(oss.str()); } +} + +/*! + * \brief prepareIdKeys - gets id keys, generates them if required + * on errors throws graft::exit_error exception + */ +void WalletAddressGraftlet::prepareIdKeys(const graft::CommonOpts& opts, crypto::public_key& W, crypto::secret_key& w) +{ + boost::filesystem::path data_path(opts.data_dir); - crypto::public_key W; boost::filesystem::path wallet_keys_file = data_path / "wallet.keys"; if (!boost::filesystem::exists(wallet_keys_file)) { LOG_PRINT_L0("file '") << wallet_keys_file << "' not found. Generating the keys"; - crypto::secret_key w; crypto::generate_keys(W, w); //save secret key boost::filesystem::path wallet_keys_file_tmp = wallet_keys_file; @@ -139,12 +203,9 @@ std::string WalletAddressGraftlet::prepareWalletKey(const graft::CommonOpts& opt throw graft::exit_error(oss.str()); } - crypto::secret_key w; - cryptonote::blobdata w_data; - bool ok = epee::string_tools::parse_hexstr_to_binbuff(w_str, w_data) || w_data.size() != sizeof(crypto::secret_key); + bool ok = parse_hexstr_to_pod(w_str, w); if(ok) { - w = *reinterpret_cast(w_data.data()); ok = crypto::secret_key_to_public_key(w,W); } if(!ok) @@ -154,8 +215,6 @@ std::string WalletAddressGraftlet::prepareWalletKey(const graft::CommonOpts& opt throw graft::exit_error(oss.str()); } } - - return epee::string_tools::pod_to_hex(W); } namespace diff --git a/graftlets/WalletAddress.h b/graftlets/WalletAddress.h index f58fdf58..17b7be9d 100644 --- a/graftlets/WalletAddress.h +++ b/graftlets/WalletAddress.h @@ -36,15 +36,13 @@ namespace graft::supernode::request { GRAFT_DEFINE_IO_STRUCT_INITED(GetWalletAddressResponse, (bool, testnet, false), (std::string, wallet_public_address, ""), - (std::string, id_key, "") + (std::string, id_key, ""), + (std::string, signature, "") //signature of wallet_public_address + ":" + id_key ); GRAFT_DEFINE_IO_STRUCT_INITED(GetWalletAddressErrorResponse, (bool, testnet, false), (std::string, error, "The wallet public address is not set") ); - -void registerGetWalletAddressRequest(graft::Router& router); - -} +} //namespace graft::supernode::request From 99fc0b6d5c7ae80a81312ed02f142c812ad38dd4 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Fri, 8 Feb 2019 18:45:18 +0200 Subject: [PATCH 11/85] Typo fixed. --- graftlets/WalletAddress.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graftlets/WalletAddress.cpp b/graftlets/WalletAddress.cpp index b17d0d80..1e10c724 100644 --- a/graftlets/WalletAddress.cpp +++ b/graftlets/WalletAddress.cpp @@ -64,8 +64,8 @@ class WalletAddressGraftlet: public IGraftlet graft::supernode::request::GetWalletAddressErrorResponse m_errorResponse; }; -GRAFTLET_EXPORTS_BEGIN("wallerAddress", GRAFTLET_MKVER(1,1)); -GRAFTLET_PLUGIN(WalletAddressGraftlet, IGraftlet, "wallerAddressGL"); +GRAFTLET_EXPORTS_BEGIN("walletAddress", GRAFTLET_MKVER(1,1)); +GRAFTLET_PLUGIN(WalletAddressGraftlet, IGraftlet, "walletAddressGL"); GRAFTLET_EXPORTS_END GRAFTLET_PLUGIN_DEFAULT_CHECK_FW_VERSION(GRAFTLET_MKVER(0,3)) From a28f8a1b5cd5cc8208a3bd5e90896746f2f56139 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Fri, 8 Feb 2019 18:47:11 +0200 Subject: [PATCH 12/85] epee::string_tools::hex_to_pod used. --- graftlets/WalletAddress.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/graftlets/WalletAddress.cpp b/graftlets/WalletAddress.cpp index 1e10c724..3c658cb6 100644 --- a/graftlets/WalletAddress.cpp +++ b/graftlets/WalletAddress.cpp @@ -70,21 +70,6 @@ GRAFTLET_EXPORTS_END GRAFTLET_PLUGIN_DEFAULT_CHECK_FW_VERSION(GRAFTLET_MKVER(0,3)) -namespace -{ - -template -bool parse_hexstr_to_pod(const std::string& s, POD& pod) -{ - cryptonote::blobdata data; - bool ok = epee::string_tools::parse_hexstr_to_binbuff(s, data) - && data.size() == sizeof(pod); - if(!ok) return false; - pod = *reinterpret_cast(data.data()); -} - -} //namespace - graft::Status WalletAddressGraftlet::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) { LOG_PRINT_L2(__FUNCTION__); @@ -135,11 +120,11 @@ void WalletAddressGraftlet::makeGetWalletAddressResponse(const graft::CommonOpts bool WalletAddressGraftlet::verifySignature() { crypto::public_key W; - bool ok = parse_hexstr_to_pod(m_response.id_key, W); + bool ok = epee::string_tools::hex_to_pod(m_response.id_key, W); assert(ok); crypto::signature sign; - bool ok1 = parse_hexstr_to_pod(m_response.signature, sign); + bool ok1 = epee::string_tools::hex_to_pod(m_response.signature, sign); assert(ok1); std::string data = m_response.wallet_public_address + ":" + m_response.id_key; @@ -203,7 +188,7 @@ void WalletAddressGraftlet::prepareIdKeys(const graft::CommonOpts& opts, crypto: throw graft::exit_error(oss.str()); } - bool ok = parse_hexstr_to_pod(w_str, w); + bool ok = epee::string_tools::hex_to_pod(w_str, w); if(ok) { ok = crypto::secret_key_to_public_key(w,W); From 02f120c8c09648a27441e433b5c80a84972c54d7 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Fri, 15 Feb 2019 14:18:18 +0200 Subject: [PATCH 13/85] class WalletAddressGraftlet renamed to WalletAddress --- graftlets/WalletAddress.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/graftlets/WalletAddress.cpp b/graftlets/WalletAddress.cpp index 3c658cb6..4997cbfe 100644 --- a/graftlets/WalletAddress.cpp +++ b/graftlets/WalletAddress.cpp @@ -42,16 +42,16 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "graftlet.WalletAddress" -class WalletAddressGraftlet: public IGraftlet +class WalletAddress: public IGraftlet { public: - WalletAddressGraftlet(const char* name) : IGraftlet(name) { } + WalletAddress(const char* name) : IGraftlet(name) { } virtual void initOnce(const graft::CommonOpts& opts) override { makeGetWalletAddressResponse(opts); - REGISTER_ENDPOINT("/dapi/v2.0/cryptonode/getwalletaddress", METHOD_GET | METHOD_POST, WalletAddressGraftlet, getWalletAddressHandler); + REGISTER_ENDPOINT("/dapi/v2.0/cryptonode/getwalletaddress", METHOD_GET | METHOD_POST, WalletAddress, getWalletAddressHandler); } private: graft::Status getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output); @@ -65,12 +65,12 @@ class WalletAddressGraftlet: public IGraftlet }; GRAFTLET_EXPORTS_BEGIN("walletAddress", GRAFTLET_MKVER(1,1)); -GRAFTLET_PLUGIN(WalletAddressGraftlet, IGraftlet, "walletAddressGL"); +GRAFTLET_PLUGIN(WalletAddress, IGraftlet, "walletAddressGL"); GRAFTLET_EXPORTS_END GRAFTLET_PLUGIN_DEFAULT_CHECK_FW_VERSION(GRAFTLET_MKVER(0,3)) -graft::Status WalletAddressGraftlet::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) +graft::Status WalletAddress::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) { LOG_PRINT_L2(__FUNCTION__); assert(ctx.local.getLastStatus() == graft::Status::None); @@ -86,7 +86,7 @@ graft::Status WalletAddressGraftlet::getWalletAddressHandler(const graft::Router /*! * \brief makeGetWalletAddressResponse - fills and signs m_response */ -void WalletAddressGraftlet::makeGetWalletAddressResponse(const graft::CommonOpts& opts) +void WalletAddress::makeGetWalletAddressResponse(const graft::CommonOpts& opts) { m_errorResponse.testnet = opts.testnet; @@ -117,7 +117,7 @@ void WalletAddressGraftlet::makeGetWalletAddressResponse(const graft::CommonOpts /*! * \brief verifySignature - only for testing here, the code can be used on the other side */ -bool WalletAddressGraftlet::verifySignature() +bool WalletAddress::verifySignature() { crypto::public_key W; bool ok = epee::string_tools::hex_to_pod(m_response.id_key, W); @@ -137,7 +137,7 @@ bool WalletAddressGraftlet::verifySignature() * \brief checkWalletPublicAddress - checks that opts.wallet_public_address is valid * on error throws graft::exit_error exception */ -void WalletAddressGraftlet::checkWalletPublicAddress(const graft::CommonOpts& opts) +void WalletAddress::checkWalletPublicAddress(const graft::CommonOpts& opts) { cryptonote::account_public_address acc = AUTO_VAL_INIT(acc); if(!cryptonote::get_account_address_from_str(acc, opts.testnet, opts.wallet_public_address)) @@ -152,7 +152,7 @@ void WalletAddressGraftlet::checkWalletPublicAddress(const graft::CommonOpts& op * \brief prepareIdKeys - gets id keys, generates them if required * on errors throws graft::exit_error exception */ -void WalletAddressGraftlet::prepareIdKeys(const graft::CommonOpts& opts, crypto::public_key& W, crypto::secret_key& w) +void WalletAddress::prepareIdKeys(const graft::CommonOpts& opts, crypto::public_key& W, crypto::secret_key& w) { boost::filesystem::path data_path(opts.data_dir); From 60bbcffc2039bec0da20462743222d9e4859dcb9 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 30 Jan 2019 09:11:00 +0300 Subject: [PATCH 14/85] Stake transaction validation on supernode --- CMakeLists.txt | 1 + include/rta/DaemonRpcClient.h | 1 + include/rta/supernode.h | 25 ++++ .../requests/send_supernode_stake_txs.h | 31 +++++ modules/cryptonode | 2 +- src/rta/DaemonRpcClient.cpp | 16 +++ src/rta/fullsupernodelist.cpp | 2 + src/rta/supernode.cpp | 22 ++++ src/supernode/requests.cpp | 2 + .../requests/send_supernode_stake_txs.cpp | 115 ++++++++++++++++++ 10 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 include/supernode/requests/send_supernode_stake_txs.h create mode 100644 src/supernode/requests/send_supernode_stake_txs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 00dda3b2..c7a53418 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,6 +280,7 @@ add_library(supernode_common STATIC ${PROJECT_SOURCE_DIR}/src/supernode/requests/sale_status.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_raw_tx.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_announce.cpp + ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_stake_txs.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_transfer.cpp ${PROJECT_SOURCE_DIR}/src/rta/DaemonRpcClient.cpp ${PROJECT_SOURCE_DIR}/src/rta/fullsupernodelist.cpp diff --git a/include/rta/DaemonRpcClient.h b/include/rta/DaemonRpcClient.h index c2fdfc03..b433cbc4 100644 --- a/include/rta/DaemonRpcClient.h +++ b/include/rta/DaemonRpcClient.h @@ -51,6 +51,7 @@ class DaemonRpcClient bool get_tx(const std::string &hash_str, cryptonote::transaction &out_tx, uint64_t &block_num, bool &mined); bool get_height(uint64_t &height); bool get_block_hash(uint64_t height, std::string &hash); + bool send_supernode_stake_txs(); protected: bool init(const std::string &daemon_address, boost::optional daemon_login); diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 52985959..9c156838 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -242,6 +242,29 @@ class Supernode */ bool busy() const; + /*! + * \brief stakeTransactionBlockHeight - height of block for stake transaction + * \return - height of block + */ + uint64_t stakeTransactionBlockHeight() const; + + /*! + * \brief setStakeTransactionBlock - set height of block for stake transaction + * \param - height of block + */ + void setStakeTransactionBlockHeight(uint64_t blockHeight); + + /*! + * \brief stakeTransactionUnlockTime - number of blocks for unlocking stake transaction + * \return + */ + uint64_t stakeTransactionUnlockTime() const; + + /*! + * \brief setStakeTransactionUnlockTime - set number of blocks for unlocking stake transaction + * \param - height of block + */ + void setStakeTransactionUnlockTime(uint64_t unlockTime); private: Supernode(bool testnet = false); @@ -255,6 +278,8 @@ class Supernode std::atomic m_last_update_time; mutable boost::shared_mutex m_wallet_guard; + std::atomic m_stake_transaction_block_height; + std::atomic m_stake_transaction_unlock_time; }; using SupernodePtr = boost::shared_ptr; diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h new file mode 100644 index 00000000..5e48df5a --- /dev/null +++ b/include/supernode/requests/send_supernode_stake_txs.h @@ -0,0 +1,31 @@ +#pragma once + +#include "lib/graft/router.h" +#include "lib/graft/inout.h" +#include "lib/graft/jsonrpc.h" + +namespace graft::supernode::request { + +GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransaction, + (std::string, hash, std::string()), + (uint64_t, block_height, 0), + (uint64_t, unlock_time, 0), + (std::string, supernode_public_id, std::string()), + (std::string, supernode_public_address, std::string()), + (std::string, tx_secret_key, std::string()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransactions, + (std::vector, stake_txs, std::vector()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(SendSupernodeStakeTransactionsResponse, + (int, Status, 0) + ); + +GRAFT_DEFINE_JSON_RPC_REQUEST(SendSupernodeStakeTransactionsJsonRpcRequest, SupernodeStakeTransactions); +GRAFT_DEFINE_JSON_RPC_RESPONSE_RESULT(SendSupernodeStakeTransactionsJsonRpcResponse, SendSupernodeStakeTransactionsResponse); + +void registerSendSupernodeStakeTransactionsRequest(graft::Router &router); + +} diff --git a/modules/cryptonode b/modules/cryptonode index d365c8e2..af65b593 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit d365c8e28a0449d1f3b2a19909788fc95833bb1b +Subproject commit af65b593bb1728431f95760054a485811e65f01a diff --git a/src/rta/DaemonRpcClient.cpp b/src/rta/DaemonRpcClient.cpp index ce7d1ba2..c8f3d9c8 100644 --- a/src/rta/DaemonRpcClient.cpp +++ b/src/rta/DaemonRpcClient.cpp @@ -172,6 +172,22 @@ bool DaemonRpcClient::get_block_hash(uint64_t height, string &hash) return true; } +bool DaemonRpcClient::send_supernode_stake_txs() +{ + epee::json_rpc::request req = AUTO_VAL_INIT(req); + epee::json_rpc::response res = AUTO_VAL_INIT(res); + req.jsonrpc = "2.0"; + req.id = epee::serialization::storage_entry(0); + req.method = "send_supernode_stake_txs"; + bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); + if (!r) { + LOG_ERROR("/rta/send_supernode_stake_txs error"); + return false; + } + + return true; +} + bool DaemonRpcClient::init(const string &daemon_address, boost::optional daemon_login) { return m_http_client.set_server(daemon_address, daemon_login); diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index dc07624d..3869b5e7 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -130,6 +130,8 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_tp(new utils::ThreadPool()) { m_refresh_counter = 0; + + m_rpc_client.send_supernode_stake_txs(); } FullSupernodeList::~FullSupernodeList() diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 122c0c60..808a4651 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -449,8 +449,30 @@ bool Supernode::busy() const } } +uint64_t Supernode::stakeTransactionBlockHeight() const +{ + return m_stake_transaction_block_height; +} + +void Supernode::setStakeTransactionBlockHeight(uint64_t blockHeight) +{ + m_stake_transaction_block_height.store(blockHeight); +} + +uint64_t Supernode::stakeTransactionUnlockTime() const +{ + return m_stake_transaction_unlock_time; +} + +void Supernode::setStakeTransactionUnlockTime(uint64_t unlockTime) +{ + m_stake_transaction_unlock_time.store(unlockTime); +} + Supernode::Supernode(bool testnet) : m_wallet{ new tools::wallet2(testnet) } +, m_stake_transaction_block_height() +, m_stake_transaction_unlock_time() { } diff --git a/src/supernode/requests.cpp b/src/supernode/requests.cpp index b52f8788..bb75d61e 100644 --- a/src/supernode/requests.cpp +++ b/src/supernode/requests.cpp @@ -15,6 +15,7 @@ #include "supernode/requests/send_raw_tx.h" #include "supernode/requests/authorize_rta_tx.h" #include "supernode/requests/send_supernode_announce.h" +#include "supernode/requests/send_supernode_stake_txs.h" namespace graft::supernode::request::debug { void __registerDebugRequests(Router& router); } namespace graft::request::system_info { void register_request(Router& router); } @@ -33,6 +34,7 @@ void registerRTARequests(graft::Router &router) registerRejectPayRequest(router); registerAuthorizeRtaTxRequests(router); registerSendSupernodeAnnounceRequest(router); + registerSendSupernodeStakeTransactionsRequest(router); } void registerWalletApiRequests(graft::Router &router) diff --git a/src/supernode/requests/send_supernode_stake_txs.cpp b/src/supernode/requests/send_supernode_stake_txs.cpp new file mode 100644 index 00000000..7a58571e --- /dev/null +++ b/src/supernode/requests/send_supernode_stake_txs.cpp @@ -0,0 +1,115 @@ +// Copyright (c) 2018, The Graft Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "supernode/requests/send_supernode_stake_txs.h" +#include "supernode/requestdefines.h" +#include "rta/fullsupernodelist.h" +#include "rta/supernode.h" + +#include +#include + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "supernode.sendsupernodestaketxsrequest" + +namespace { + static const char* PATH = "/send_supernode_stake_txs"; +} + +namespace graft::supernode::request { + +namespace +{ + +Status supernodeStakeTransactionsHandler + (const Router::vars_t& vars, + const graft::Input& input, + graft::Context& ctx, + graft::Output& output) +{ + LOG_PRINT_L1(PATH << " called with payload: " << input.data()); + + boost::shared_ptr fsl = ctx.global.get("fsl", boost::shared_ptr()); + SupernodePtr supernode = ctx.global.get("supernode", SupernodePtr()); + + if (!fsl.get()) { + LOG_ERROR("Internal error. Supernode list object missing"); + return Status::Error; + } + + if (!supernode.get()) { + LOG_ERROR("Internal error. Supernode object missing"); + return Status::Error; + } + + SendSupernodeStakeTransactionsJsonRpcRequest req; + + if (!input.get(req)) + { + // can't parse request + LOG_ERROR("Failed to parse request"); + return Status::Error; + } + + // handle stake Transactions + const std::vector& stake_txs = req.params.stake_txs; + + for (const SupernodeStakeTransaction& tx : stake_txs) + { + if (!fsl->exists(tx.supernode_public_address)) + continue; + + // check if supernode currently busy + SupernodePtr sn = fsl->get(tx.supernode_public_address); + + if (sn->busy()) { + MWARNING("Unable to update supernode with new stake transactions: " << tx.supernode_public_address << ", BUSY"); + return Status::Error; + } + + //TODO: should check supernode == sn? + + sn->setStakeTransactionBlockHeight(tx.block_height); + sn->setStakeTransactionUnlockTime(tx.unlock_time); + } + + return Status::Ok; +} + +} + +void registerSendSupernodeStakeTransactionsRequest(graft::Router &router) +{ + Router::Handler3 h3(nullptr, supernodeStakeTransactionsHandler, nullptr); + + router.addRoute(PATH, METHOD_POST, h3); + + LOG_PRINT_L0("route " << PATH << " registered"); +} + +} From 802c5f524547b4bc5d4cf2e2b863cdcf9c073d6c Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Tue, 12 Feb 2019 01:58:12 +0200 Subject: [PATCH 15/85] Adding supernode signature to stake transaction --- .../requests/send_supernode_stake_txs.h | 1 + modules/cryptonode | 2 +- .../requests/send_supernode_stake_txs.cpp | 29 ++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h index 5e48df5a..184b8eea 100644 --- a/include/supernode/requests/send_supernode_stake_txs.h +++ b/include/supernode/requests/send_supernode_stake_txs.h @@ -12,6 +12,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransaction, (uint64_t, unlock_time, 0), (std::string, supernode_public_id, std::string()), (std::string, supernode_public_address, std::string()), + (std::string, supernode_signature, std::string()), (std::string, tx_secret_key, std::string()) ); diff --git a/modules/cryptonode b/modules/cryptonode index af65b593..b35f3df6 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit af65b593bb1728431f95760054a485811e65f01a +Subproject commit b35f3df61c5df5f501b62f2196efa4382f961221 diff --git a/src/supernode/requests/send_supernode_stake_txs.cpp b/src/supernode/requests/send_supernode_stake_txs.cpp index 7a58571e..ccc9aba0 100644 --- a/src/supernode/requests/send_supernode_stake_txs.cpp +++ b/src/supernode/requests/send_supernode_stake_txs.cpp @@ -46,6 +46,28 @@ namespace graft::supernode::request { namespace { +bool verifySignature(const std::string& id_key, const std::string& wallet_public_address, const std::string& signature) +{ + crypto::public_key W; + if (!epee::string_tools::hex_to_pod(id_key, W)) + { + LOG_ERROR("Invalid supernode public identifier '" << id_key << "'"); + return false; + } + + crypto::signature sign; + if (!epee::string_tools::hex_to_pod(signature, sign)) + { + LOG_ERROR("Invalid supernode signature '" << signature << "'"); + return false; + } + + std::string data = wallet_public_address + ":" + id_key; + crypto::hash hash; + crypto::cn_fast_hash(data.data(), data.size(), hash); + return crypto::check_signature(hash, W, sign); +} + Status supernodeStakeTransactionsHandler (const Router::vars_t& vars, const graft::Input& input, @@ -92,7 +114,12 @@ Status supernodeStakeTransactionsHandler return Status::Error; } - //TODO: should check supernode == sn? + if (!verifySignature(tx.supernode_public_id, tx.supernode_public_address, tx.supernode_signature)) + { + LOG_ERROR("Supernode signature failed for supernode_public_id='" << tx.supernode_public_id <<"', supernode_public_address='" << + tx.supernode_public_address << "', signature='" << tx.supernode_signature << "'"); + return Status::Error; + } sn->setStakeTransactionBlockHeight(tx.block_height); sn->setStakeTransactionUnlockTime(tx.unlock_time); From bc353c193f1efce524bf287394c4728b2f247cc5 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Tue, 12 Feb 2019 16:43:05 +0200 Subject: [PATCH 16/85] Stake transactions batch update --- include/rta/fullsupernodelist.h | 17 +++++ include/rta/supernode.h | 21 +++--- .../requests/send_supernode_stake_txs.h | 2 + modules/cryptonode | 2 +- src/rta/fullsupernodelist.cpp | 66 +++++++++++++++++++ src/rta/supernode.cpp | 8 ++- .../requests/send_supernode_stake_txs.cpp | 61 +++++------------ 7 files changed, 122 insertions(+), 55 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 2210745e..536c0cf7 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -126,6 +126,23 @@ class FullSupernodeList */ size_t refreshedItems() const; + struct stake_transaction + { + uint64_t amount = 0; + uint64_t block_height = 0; + uint64_t unlock_time = 0; + std::string supernode_public_id; + std::string supernode_public_address; + std::string supernode_signature; + }; + typedef std::vector stake_transaction_array; + + /*! + * \brief updateStakeTransactions - update stake transactions + * \param - array of stake transactions + * \return + */ + void updateStakeTransactions(const stake_transaction_array& stake_txs); private: bool loadWallet(const std::string &wallet_path); diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 9c156838..9a6712a9 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -28,14 +29,10 @@ class Supernode public: using SignedKeyImage = std::pair; - // 50,000 GRFT – tier 1 - // 90,000 GRFT – tier 2 - // 150,000 GRFT – tier 3 - // 250,000 GRFT – tier 4 - static constexpr uint64_t TIER1_STAKE_AMOUNT = COIN * 50000; - static constexpr uint64_t TIER2_STAKE_AMOUNT = COIN * 90000; - static constexpr uint64_t TIER3_STAKE_AMOUNT = COIN * 150000; - static constexpr uint64_t TIER4_STAKE_AMOUNT = COIN * 250000; + static constexpr uint64_t TIER1_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; + static constexpr uint64_t TIER2_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; + static constexpr uint64_t TIER3_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; + static constexpr uint64_t TIER4_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; /*! * \brief Supernode - constructs supernode @@ -74,6 +71,13 @@ class Supernode * \return - stake amount in atomic units */ uint64_t stakeAmount() const; + + /*! + * \brief setStakeAmount - set stake amount + * \param - amount + */ + void setStakeAmount(uint64_t amount); + /*! * \brief tier - returns the tier of this supernode based on its stake amount * \return - the tier (1-4) of the supernode or 0 if the verified stake amount is below tier 1 @@ -278,6 +282,7 @@ class Supernode std::atomic m_last_update_time; mutable boost::shared_mutex m_wallet_guard; + std::atomic m_stake_amount; std::atomic m_stake_transaction_block_height; std::atomic m_stake_transaction_unlock_time; }; diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h index 184b8eea..42853be6 100644 --- a/include/supernode/requests/send_supernode_stake_txs.h +++ b/include/supernode/requests/send_supernode_stake_txs.h @@ -8,6 +8,8 @@ namespace graft::supernode::request { GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransaction, (std::string, hash, std::string()), + (uint64_t, amount, 0), + (uint32_t, tier, 0), (uint64_t, block_height, 0), (uint64_t, unlock_time, 0), (std::string, supernode_public_id, std::string()), diff --git a/modules/cryptonode b/modules/cryptonode index b35f3df6..ac719c71 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit b35f3df61c5df5f501b62f2196efa4382f961221 +Subproject commit ac719c71d8bdb00afad19ecc9eb0911221d22fdb diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 3869b5e7..47927cbd 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -372,6 +372,72 @@ bool FullSupernodeList::loadWallet(const std::string &wallet_path) return result; } +namespace +{ + +bool verifySignature(const std::string& id_key, const std::string& wallet_public_address, const std::string& signature) +{ + crypto::public_key W; + if (!epee::string_tools::hex_to_pod(id_key, W)) + { + LOG_ERROR("Invalid supernode public identifier '" << id_key << "'"); + return false; + } + + crypto::signature sign; + if (!epee::string_tools::hex_to_pod(signature, sign)) + { + LOG_ERROR("Invalid supernode signature '" << signature << "'"); + return false; + } + + std::string data = wallet_public_address + ":" + id_key; + crypto::hash hash; + crypto::cn_fast_hash(data.data(), data.size(), hash); + return crypto::check_signature(hash, W, sign); +} + +} + +void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs) +{ + boost::unique_lock writerLock(m_access); + + //reset current stake transactions state + + for (const std::unordered_map::value_type& sn_desc : m_list) + { + SupernodePtr sn = sn_desc.second; + + if (!sn) + continue; + + sn->setStakeAmount(0); + sn->setStakeTransactionBlockHeight(0); + sn->setStakeTransactionUnlockTime(0); + } + + //apply new stake transactions state + + for (const stake_transaction& tx : stake_txs) + { + SupernodePtr sn = get(tx.supernode_public_address); + + if (!sn) + continue; + + if (!verifySignature(tx.supernode_public_id, tx.supernode_public_address, tx.supernode_signature)) + { + LOG_ERROR("Supernode signature failed for supernode_public_id='" << tx.supernode_public_id << "', supernode_public_address='" << + tx.supernode_public_address << "', signature='" << tx.supernode_signature << "'"); + continue; + } + + sn->setStakeAmount(tx.amount); + sn->setStakeTransactionBlockHeight(tx.block_height); + sn->setStakeTransactionUnlockTime(tx.unlock_time); + } +} std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 808a4651..8aae8fa0 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -80,8 +80,12 @@ Supernode::~Supernode() uint64_t Supernode::stakeAmount() const { - boost::shared_lock readLock(m_wallet_guard); - return m_wallet->unspent_balance(); + return m_stake_amount; +} + +void Supernode::setStakeAmount(uint64_t amount) +{ + m_stake_amount = amount; } uint32_t Supernode::tier() const diff --git a/src/supernode/requests/send_supernode_stake_txs.cpp b/src/supernode/requests/send_supernode_stake_txs.cpp index ccc9aba0..882021bc 100644 --- a/src/supernode/requests/send_supernode_stake_txs.cpp +++ b/src/supernode/requests/send_supernode_stake_txs.cpp @@ -46,28 +46,6 @@ namespace graft::supernode::request { namespace { -bool verifySignature(const std::string& id_key, const std::string& wallet_public_address, const std::string& signature) -{ - crypto::public_key W; - if (!epee::string_tools::hex_to_pod(id_key, W)) - { - LOG_ERROR("Invalid supernode public identifier '" << id_key << "'"); - return false; - } - - crypto::signature sign; - if (!epee::string_tools::hex_to_pod(signature, sign)) - { - LOG_ERROR("Invalid supernode signature '" << signature << "'"); - return false; - } - - std::string data = wallet_public_address + ":" + id_key; - crypto::hash hash; - crypto::cn_fast_hash(data.data(), data.size(), hash); - return crypto::check_signature(hash, W, sign); -} - Status supernodeStakeTransactionsHandler (const Router::vars_t& vars, const graft::Input& input, @@ -99,32 +77,27 @@ Status supernodeStakeTransactionsHandler } // handle stake Transactions - const std::vector& stake_txs = req.params.stake_txs; + const std::vector& src_stake_txs = req.params.stake_txs; + FullSupernodeList::stake_transaction_array dst_stake_txs; + + dst_stake_txs.reserve(src_stake_txs.size()); - for (const SupernodeStakeTransaction& tx : stake_txs) + for (const SupernodeStakeTransaction& src_tx : src_stake_txs) { - if (!fsl->exists(tx.supernode_public_address)) - continue; - - // check if supernode currently busy - SupernodePtr sn = fsl->get(tx.supernode_public_address); - - if (sn->busy()) { - MWARNING("Unable to update supernode with new stake transactions: " << tx.supernode_public_address << ", BUSY"); - return Status::Error; - } - - if (!verifySignature(tx.supernode_public_id, tx.supernode_public_address, tx.supernode_signature)) - { - LOG_ERROR("Supernode signature failed for supernode_public_id='" << tx.supernode_public_id <<"', supernode_public_address='" << - tx.supernode_public_address << "', signature='" << tx.supernode_signature << "'"); - return Status::Error; - } - - sn->setStakeTransactionBlockHeight(tx.block_height); - sn->setStakeTransactionUnlockTime(tx.unlock_time); + FullSupernodeList::stake_transaction dst_tx; + + dst_tx.amount = src_tx.amount; + dst_tx.block_height = src_tx.block_height; + dst_tx.unlock_time = src_tx.unlock_time; + dst_tx.supernode_public_id = src_tx.supernode_public_id; + dst_tx.supernode_public_address = src_tx.supernode_public_address; + dst_tx.supernode_signature = src_tx.supernode_signature; + + dst_stake_txs.emplace_back(std::move(dst_tx)); } + fsl->updateStakeTransactions(dst_stake_txs); + return Status::Ok; } From dc97325a51e37e481b4d094df73342bc5db91922 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 14 Feb 2019 18:00:04 +0200 Subject: [PATCH 17/85] Update stake transaction fields for RPC --- include/supernode/requests/send_supernode_stake_txs.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h index 42853be6..a2d8e44d 100644 --- a/include/supernode/requests/send_supernode_stake_txs.h +++ b/include/supernode/requests/send_supernode_stake_txs.h @@ -14,8 +14,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransaction, (uint64_t, unlock_time, 0), (std::string, supernode_public_id, std::string()), (std::string, supernode_public_address, std::string()), - (std::string, supernode_signature, std::string()), - (std::string, tx_secret_key, std::string()) + (std::string, supernode_signature, std::string()) ); GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransactions, From e3a4c4417384b48af7c92b40ba2b2749b735b977 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 14 Feb 2019 19:12:47 +0200 Subject: [PATCH 18/85] Move signature verification of stake transactions to cryptonode --- include/rta/fullsupernodelist.h | 1 - .../requests/send_supernode_stake_txs.h | 3 +- src/rta/fullsupernodelist.cpp | 34 ------------------- .../requests/send_supernode_stake_txs.cpp | 1 - 4 files changed, 1 insertion(+), 38 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 536c0cf7..416a5436 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -133,7 +133,6 @@ class FullSupernodeList uint64_t unlock_time = 0; std::string supernode_public_id; std::string supernode_public_address; - std::string supernode_signature; }; typedef std::vector stake_transaction_array; diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h index a2d8e44d..6a7b5eb6 100644 --- a/include/supernode/requests/send_supernode_stake_txs.h +++ b/include/supernode/requests/send_supernode_stake_txs.h @@ -13,8 +13,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransaction, (uint64_t, block_height, 0), (uint64_t, unlock_time, 0), (std::string, supernode_public_id, std::string()), - (std::string, supernode_public_address, std::string()), - (std::string, supernode_signature, std::string()) + (std::string, supernode_public_address, std::string()) ); GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransactions, diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 47927cbd..36873e21 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -372,33 +372,6 @@ bool FullSupernodeList::loadWallet(const std::string &wallet_path) return result; } -namespace -{ - -bool verifySignature(const std::string& id_key, const std::string& wallet_public_address, const std::string& signature) -{ - crypto::public_key W; - if (!epee::string_tools::hex_to_pod(id_key, W)) - { - LOG_ERROR("Invalid supernode public identifier '" << id_key << "'"); - return false; - } - - crypto::signature sign; - if (!epee::string_tools::hex_to_pod(signature, sign)) - { - LOG_ERROR("Invalid supernode signature '" << signature << "'"); - return false; - } - - std::string data = wallet_public_address + ":" + id_key; - crypto::hash hash; - crypto::cn_fast_hash(data.data(), data.size(), hash); - return crypto::check_signature(hash, W, sign); -} - -} - void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs) { boost::unique_lock writerLock(m_access); @@ -426,13 +399,6 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s if (!sn) continue; - if (!verifySignature(tx.supernode_public_id, tx.supernode_public_address, tx.supernode_signature)) - { - LOG_ERROR("Supernode signature failed for supernode_public_id='" << tx.supernode_public_id << "', supernode_public_address='" << - tx.supernode_public_address << "', signature='" << tx.supernode_signature << "'"); - continue; - } - sn->setStakeAmount(tx.amount); sn->setStakeTransactionBlockHeight(tx.block_height); sn->setStakeTransactionUnlockTime(tx.unlock_time); diff --git a/src/supernode/requests/send_supernode_stake_txs.cpp b/src/supernode/requests/send_supernode_stake_txs.cpp index 882021bc..dd273173 100644 --- a/src/supernode/requests/send_supernode_stake_txs.cpp +++ b/src/supernode/requests/send_supernode_stake_txs.cpp @@ -91,7 +91,6 @@ Status supernodeStakeTransactionsHandler dst_tx.unlock_time = src_tx.unlock_time; dst_tx.supernode_public_id = src_tx.supernode_public_id; dst_tx.supernode_public_address = src_tx.supernode_public_address; - dst_tx.supernode_signature = src_tx.supernode_signature; dst_stake_txs.emplace_back(std::move(dst_tx)); } From f99164ff1911c22d182e3d575ecb995c71b7980a Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Fri, 22 Feb 2019 14:03:03 +0200 Subject: [PATCH 19/85] Use graft_rta_config.h with constants for RTA validation process --- include/rta/supernode.h | 10 +++++----- modules/cryptonode | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 9a6712a9..945cb8be 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -29,10 +29,10 @@ class Supernode public: using SignedKeyImage = std::pair; - static constexpr uint64_t TIER1_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; - static constexpr uint64_t TIER2_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; - static constexpr uint64_t TIER3_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; - static constexpr uint64_t TIER4_STAKE_AMOUNT = cryptonote::StakeTransactionProcessor::TIER1_STAKE_AMOUNT; + static constexpr uint64_t TIER1_STAKE_AMOUNT = config::graft::TIER1_STAKE_AMOUNT; + static constexpr uint64_t TIER2_STAKE_AMOUNT = config::graft::TIER2_STAKE_AMOUNT; + static constexpr uint64_t TIER3_STAKE_AMOUNT = config::graft::TIER3_STAKE_AMOUNT; + static constexpr uint64_t TIER4_STAKE_AMOUNT = config::graft::TIER4_STAKE_AMOUNT; /*! * \brief Supernode - constructs supernode diff --git a/modules/cryptonode b/modules/cryptonode index ac719c71..e0118358 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit ac719c71d8bdb00afad19ecc9eb0911221d22fdb +Subproject commit e0118358d55082b3a0c2773d731f24adc1f3105c From 0a80449e518567828bdcaff8b5c01572a343e036 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Fri, 22 Feb 2019 18:16:20 +0200 Subject: [PATCH 20/85] Fix for stake transaction transfer between supernode and cryptonode --- include/rta/DaemonRpcClient.h | 2 +- include/rta/fullsupernodelist.h | 6 ++++ .../requests/send_supernode_stake_txs.h | 2 +- include/supernode/supernode.h | 1 + modules/cryptonode | 2 +- src/rta/DaemonRpcClient.cpp | 6 ++-- src/rta/fullsupernodelist.cpp | 7 +++-- src/supernode/supernode.cpp | 29 +++++++++++++++++++ 8 files changed, 48 insertions(+), 7 deletions(-) diff --git a/include/rta/DaemonRpcClient.h b/include/rta/DaemonRpcClient.h index b433cbc4..6a11a128 100644 --- a/include/rta/DaemonRpcClient.h +++ b/include/rta/DaemonRpcClient.h @@ -51,7 +51,7 @@ class DaemonRpcClient bool get_tx(const std::string &hash_str, cryptonote::transaction &out_tx, uint64_t &block_num, bool &mined); bool get_height(uint64_t &height); bool get_block_hash(uint64_t height, std::string &hash); - bool send_supernode_stake_txs(); + bool send_supernode_stake_txs(const char* network_address, const char* address); protected: bool init(const std::string &daemon_address, boost::optional daemon_login); diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 416a5436..11a46cf8 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -143,6 +143,12 @@ class FullSupernodeList */ void updateStakeTransactions(const stake_transaction_array& stake_txs); + /*! + * \brief refreshedStakeTransactions - request stake transactions from cryptonode + * \return + */ + void refreshStakeTransactions(const char* supernode_network_address, const char* supernode_address); + private: bool loadWallet(const std::string &wallet_path); diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h index 6a7b5eb6..9f6fedb6 100644 --- a/include/supernode/requests/send_supernode_stake_txs.h +++ b/include/supernode/requests/send_supernode_stake_txs.h @@ -21,7 +21,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransactions, ); GRAFT_DEFINE_IO_STRUCT_INITED(SendSupernodeStakeTransactionsResponse, - (int, Status, 0) + (int, status, 0) ); GRAFT_DEFINE_JSON_RPC_REQUEST(SendSupernodeStakeTransactionsJsonRpcRequest, SupernodeStakeTransactions); diff --git a/include/supernode/supernode.h b/include/supernode/supernode.h index a99af49b..4833b7ec 100644 --- a/include/supernode/supernode.h +++ b/include/supernode/supernode.h @@ -22,6 +22,7 @@ class Supernode : public GraftServer void setHttpRouters(ConnectionManager& httpcm); void setCoapRouters(ConnectionManager& coapcm); void loadStakeWallets(); + void requestStakeTransactions(); ConfigOptsEx m_configEx; protected: diff --git a/modules/cryptonode b/modules/cryptonode index e0118358..7295b78d 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit e0118358d55082b3a0c2773d731f24adc1f3105c +Subproject commit 7295b78d339189fc896e529be6e4e81a0cf56532 diff --git a/src/rta/DaemonRpcClient.cpp b/src/rta/DaemonRpcClient.cpp index c8f3d9c8..253e555d 100644 --- a/src/rta/DaemonRpcClient.cpp +++ b/src/rta/DaemonRpcClient.cpp @@ -172,16 +172,18 @@ bool DaemonRpcClient::get_block_hash(uint64_t height, string &hash) return true; } -bool DaemonRpcClient::send_supernode_stake_txs() +bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, const char* address) { epee::json_rpc::request req = AUTO_VAL_INIT(req); epee::json_rpc::response res = AUTO_VAL_INIT(res); req.jsonrpc = "2.0"; req.id = epee::serialization::storage_entry(0); req.method = "send_supernode_stake_txs"; + req.params.network_address = network_address; + req.params.address = address; bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); if (!r) { - LOG_ERROR("/rta/send_supernode_stake_txs error"); + LOG_ERROR("/json_rpc/rta/send_supernode_stake_txs error"); return false; } diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 36873e21..efc1eede 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -130,8 +130,6 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_tp(new utils::ThreadPool()) { m_refresh_counter = 0; - - m_rpc_client.send_supernode_stake_txs(); } FullSupernodeList::~FullSupernodeList() @@ -405,6 +403,11 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s } } +void FullSupernodeList::refreshStakeTransactions(const char* network_address, const char* address) +{ + m_rpc_client.send_supernode_stake_txs(network_address, address); +} + std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { for (size_t i = 0; i < supernodes.size(); ++i) { diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index da82f25a..1be7b15a 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -109,6 +109,35 @@ void Supernode::initMisc(ConfigOpts& configOpts) auto deferred_task = [duration, this] () { std::this_thread::sleep_for(duration); this->loadStakeWallets(); }; std::thread t(deferred_task); t.detach(); + + requestStakeTransactions(); +} + +void Supernode::requestStakeTransactions() +{ + auto handler = [](const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output)->graft::Status + { + graft::SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, graft::SupernodePtr(nullptr)); + + if (!supernode.get()) { + LOG_ERROR("supernode is not set in global context"); + return graft::Status::Error; + } + + if (FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr())) + { + fsl->refreshStakeTransactions(supernode->networkAddress().c_str(), supernode->walletAddress().c_str()); + } + + return graft::Status::Stop; + }; + + static const size_t STAKE_TRANSACTIONS_REQUEST_DELAY_MS = 1000; + + getConnectionBase().getLooper().addPeriodicTask( + graft::Router::Handler3(nullptr, handler, nullptr), + std::chrono::milliseconds(STAKE_TRANSACTIONS_REQUEST_DELAY_MS) + ); } void Supernode::startSupernodePeriodicTasks() From 8625649dd848a6367ad83615504a8595c7438d0a Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 27 Feb 2019 11:27:59 +0200 Subject: [PATCH 21/85] Update cryptonode --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 7295b78d..3ddfbfd3 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 7295b78d339189fc896e529be6e4e81a0cf56532 +Subproject commit 3ddfbfd3c12f7e4d5756e7ee2df45f1add14ca2f From 5e2044d096207edcedc4cf5a823c79697602f6a3 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 27 Feb 2019 14:38:06 +0200 Subject: [PATCH 22/85] Remove lock from stake transactions updating --- src/rta/fullsupernodelist.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index efc1eede..7e9edfd6 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -373,7 +373,6 @@ bool FullSupernodeList::loadWallet(const std::string &wallet_path) void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs) { boost::unique_lock writerLock(m_access); - //reset current stake transactions state for (const std::unordered_map::value_type& sn_desc : m_list) @@ -392,10 +391,10 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s for (const stake_transaction& tx : stake_txs) { - SupernodePtr sn = get(tx.supernode_public_address); - - if (!sn) + auto it = m_list.find(tx.supernode_public_address); + if (it == m_list.end()) continue; + SupernodePtr sn = it->second; sn->setStakeAmount(tx.amount); sn->setStakeTransactionBlockHeight(tx.block_height); From b5130fe0d21fcefa0e69069263bc8a7428e287c5 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 27 Feb 2019 15:03:23 +0200 Subject: [PATCH 23/85] Automatic update stakes for new supernodes --- include/rta/fullsupernodelist.h | 2 ++ src/rta/fullsupernodelist.cpp | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 11a46cf8..7623f756 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -151,9 +151,11 @@ class FullSupernodeList private: bool loadWallet(const std::string &wallet_path); + void updateStakeTransactionsImpl(); private: std::unordered_map m_list; + stake_transaction_array m_stake_txs; std::string m_daemon_address; bool m_testnet; DaemonRpcClient m_rpc_client; diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 7e9edfd6..376a3299 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -154,6 +154,7 @@ bool FullSupernodeList::add(SupernodePtr item) m_list.insert(std::make_pair(item->walletAddress(), item)); LOG_PRINT_L1("added supernode: " << item->walletAddress()); LOG_PRINT_L1("list size: " << m_list.size()); + updateStakeTransactionsImpl(); return true; } @@ -313,9 +314,9 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, vector &o vector FullSupernodeList::items() const { + boost::shared_lock readerLock(m_access); vector result; result.reserve(m_list.size()); - boost::shared_lock readerLock(m_access); for (auto const& it: m_list) result.push_back(it.first); @@ -373,8 +374,11 @@ bool FullSupernodeList::loadWallet(const std::string &wallet_path) void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs) { boost::unique_lock writerLock(m_access); + //reset current stake transactions state + m_stake_txs.clear(); + for (const std::unordered_map::value_type& sn_desc : m_list) { SupernodePtr sn = sn_desc.second; @@ -389,11 +393,22 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s //apply new stake transactions state - for (const stake_transaction& tx : stake_txs) + m_stake_txs = stake_txs; + + updateStakeTransactionsImpl(); +} + +void FullSupernodeList::updateStakeTransactionsImpl() +{ + MDEBUG("update stake transactions"); + + for (const stake_transaction& tx : m_stake_txs) { auto it = m_list.find(tx.supernode_public_address); + if (it == m_list.end()) continue; + SupernodePtr sn = it->second; sn->setStakeAmount(tx.amount); From d4e8d130ca7c8c04e6bb0eefe7336b023038b8ec Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 27 Feb 2019 15:14:45 +0200 Subject: [PATCH 24/85] Stake amount fix for supernode --- src/rta/supernode.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 8aae8fa0..166b6534 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -31,6 +31,9 @@ Supernode::Supernode(const string &wallet_path, const string &wallet_password, c const string &seed_language) : m_wallet{new tools::wallet2(testnet, false, Supernode::m_ioservice)} , m_last_update_time {0} + , m_stake_amount() + , m_stake_transaction_block_height() + , m_stake_transaction_unlock_time() { bool keys_file_exists; bool wallet_file_exists; From c7dc17551f52f786120d126a3f109f41e70c3e46 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Tue, 5 Feb 2019 16:20:18 +0200 Subject: [PATCH 25/85] Auth sample building using blockchain based list --- CMakeLists.txt | 1 + include/rta/fullsupernodelist.h | 21 ++- .../requests/blockchain_based_list.h | 31 +++++ modules/cryptonode | 2 +- src/rta/fullsupernodelist.cpp | 106 +++++++++++---- src/supernode/requests.cpp | 2 + .../requests/blockchain_based_list.cpp | 122 ++++++++++++++++++ src/supernode/requests/debug.cpp | 6 +- src/supernode/requests/pay.cpp | 4 +- src/supernode/requests/sale.cpp | 2 +- src/supernode/requests/sale_details.cpp | 4 +- test/rta_classes_test.cpp | 4 +- 12 files changed, 268 insertions(+), 37 deletions(-) create mode 100644 include/supernode/requests/blockchain_based_list.h create mode 100644 src/supernode/requests/blockchain_based_list.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c7a53418..ec3c09db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,6 +282,7 @@ add_library(supernode_common STATIC ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_announce.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_stake_txs.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_transfer.cpp + ${PROJECT_SOURCE_DIR}/src/supernode/requests/blockchain_based_list.cpp ${PROJECT_SOURCE_DIR}/src/rta/DaemonRpcClient.cpp ${PROJECT_SOURCE_DIR}/src/rta/fullsupernodelist.cpp ${PROJECT_SOURCE_DIR}/src/rta/supernode.cpp diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 7623f756..fdbaa96f 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -93,10 +93,11 @@ class FullSupernodeList /*! * \brief buildAuthSample - builds auth sample (8 supernodes) for given block height * \param height - block height used to perform selection + * \param payment_id - payment id which is used for building auth sample * \param out - vector of supernode pointers * \return - true on success */ - bool buildAuthSample(uint64_t height, std::vector &out); + bool buildAuthSample(uint64_t height, const std::string& payment_id, std::vector &out); /*! * \brief items - returns address list of known supernodes @@ -142,6 +143,21 @@ class FullSupernodeList * \return */ void updateStakeTransactions(const stake_transaction_array& stake_txs); + + typedef std::vector SupernodeArray; + typedef std::vector SupernodeTierArray; + + /*! + * \brief setBlockchainBasedList - updates full list of supernodes + * \return + */ + void setBlockchainBasedList(uint64_t block_number, const SupernodeTierArray& tiers); + + /*! + * \brief blockchainBasedListBlockNumber - number of block which blockchain list is built for + * \return + */ + uint64_t blockchainBasedListBlockNumber() const; /*! * \brief refreshedStakeTransactions - request stake transactions from cryptonode @@ -152,6 +168,7 @@ class FullSupernodeList private: bool loadWallet(const std::string &wallet_path); void updateStakeTransactionsImpl(); + void selectSupernodes(const std::string& payment_id, const SupernodeArray& src_array, SupernodeArray& dst_array); private: std::unordered_map m_list; @@ -162,6 +179,8 @@ class FullSupernodeList mutable boost::shared_mutex m_access; std::unique_ptr m_tp; std::atomic_size_t m_refresh_counter; + uint64_t m_blockchain_based_list_block_number; + SupernodeTierArray m_blockchain_based_list; //TODO: lifetime of supernodes, should this be an array of weak pointers? }; using FullSupernodeListPtr = boost::shared_ptr; diff --git a/include/supernode/requests/blockchain_based_list.h b/include/supernode/requests/blockchain_based_list.h new file mode 100644 index 00000000..565d8de4 --- /dev/null +++ b/include/supernode/requests/blockchain_based_list.h @@ -0,0 +1,31 @@ +#pragma once + +#include "lib/graft/router.h" +#include "lib/graft/inout.h" +#include "lib/graft/jsonrpc.h" + +namespace graft::supernode::request { + +GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTierEntry, + (std::string, supernode_public_id, std::string()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTier, + (std::vector, supernodes, std::vector()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedList, + (uint64_t, block_number, uint64_t()), + (std::vector, tiers, std::vector()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListResponse, + (int, Status, 0) + ); + +GRAFT_DEFINE_JSON_RPC_REQUEST(BlockchainBasedListJsonRpcRequest, BlockchainBasedList); +GRAFT_DEFINE_JSON_RPC_RESPONSE_RESULT(BlockchainBasedListJsonRpcResponse, BlockchainBasedListResponse); + +void registerBlockchainBasedListRequest(graft::Router &router); + +} diff --git a/modules/cryptonode b/modules/cryptonode index 3ddfbfd3..6b796e56 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 3ddfbfd3c12f7e4d5756e7ee2df45f1add14ca2f +Subproject commit 6b796e566780b1cbeaafe338d1bc24e26dc1ccef diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 376a3299..d5c32788 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -128,6 +128,7 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_testnet(testnet) , m_rpc_client(daemon_address, "", "") , m_tp(new utils::ThreadPool()) + , m_blockchain_based_list_block_number() { m_refresh_counter = 0; } @@ -227,32 +228,79 @@ SupernodePtr FullSupernodeList::get(const string &address) const return SupernodePtr(nullptr); } -bool FullSupernodeList::buildAuthSample(uint64_t height, vector &out) +void FullSupernodeList::selectSupernodes(const std::string& payment_id, const SupernodeArray& src_array, SupernodeArray& dst_array) { - crypto::hash block_hash; - string block_hash_str; + const char* it = payment_id.c_str(); + const size_t supernodes_count = src_array.size(); - MDEBUG("building auth sample for height: " << height); + for (bool loop=true; loop && it[0] && it[1];) + { + if (*it == '-') + { + it++; + continue; + } - if (!getBlockHash(height - AUTH_SAMPLE_HASH_HEIGHT, block_hash_str)) { - LOG_ERROR("getBlockHash error"); - return false; + char buffer[] = {it[0], it[1], 0}; + size_t base_index = strtoul(buffer, nullptr, 16); + + it += 2; + + for (size_t offset=0;; offset++) + { + if (offset == supernodes_count) + { + loop = false; + break; //all supernodes have been selected + } + + size_t supernode_index = (offset + base_index) % supernodes_count; + SupernodePtr supernode = src_array[supernode_index]; + bool already_selected = false; + + for (const SupernodePtr& supernode_it : dst_array) + { + if (supernode_it == supernode) + { + already_selected = true; + break; + } + } + + if (already_selected) + continue; + + dst_array.push_back(supernode); + + break; + } } +} - epee::string_tools::hex_to_pod(block_hash_str, block_hash); +bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, vector &out) +{ + MDEBUG("building auth sample for height " << height << " and PaymentID " << payment_id); + + std::array tier_supernodes; - std::array, TIERS> tier_supernodes; { boost::shared_lock readerLock(m_access); - int64_t now = static_cast(std::time(nullptr)); - int64_t cutoff_time = now - ANNOUNCE_TTL_SECONDS; - for (const auto &sn_pair : m_list) { - const auto &sn = sn_pair.second; - const auto tier = sn->tier(); - MTRACE("checking supernode " << sn_pair.first << ", updated: " << (now - sn->lastUpdateTime()) << "s ago" - << ", tier: " << tier); - if (tier > 0 && sn->lastUpdateTime() >= cutoff_time) - tier_supernodes[tier - 1].push_back(sn); + + if (height != m_blockchain_based_list_block_number) + { + LOG_ERROR("unable to build auth sample for block height " << height << " and PaymentID " + << payment_id << " because of mistmatch with blockchain based list block number " << m_blockchain_based_list_block_number); + return false; + } + + for (size_t i=0; i &o out.reserve(ITEMS_PER_TIER * TIERS); auto out_it = back_inserter(out); for (int i = 0; i < TIERS; i++) { - std::partial_sort( - tier_supernodes[i].begin(), tier_supernodes[i].begin() + select[i], tier_supernodes[i].end(), - [&](const SupernodePtr a, const SupernodePtr b) { - crypto::hash hash_a, hash_b; - a->getScoreHash(block_hash, hash_a); - b->getScoreHash(block_hash, hash_b); - return hash_to_int256(hash_a) < hash_to_int256(hash_b); - }); std::copy(tier_supernodes[i].begin(), tier_supernodes[i].begin() + select[i], out_it); } @@ -422,6 +462,20 @@ void FullSupernodeList::refreshStakeTransactions(const char* network_address, co m_rpc_client.send_supernode_stake_txs(network_address, address); } +void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const SupernodeTierArray& tiers) +{ + boost::unique_lock writerLock(m_access); + + if (block_number <= m_blockchain_based_list_block_number) + { + MDEBUG("Blockchain based list is obsolete. Incoming list was built for block " << block_number << ", actual block is " << m_blockchain_based_list_block_number); + return; + } + + m_blockchain_based_list = tiers; + m_blockchain_based_list_block_number = block_number; +} + std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { for (size_t i = 0; i < supernodes.size(); ++i) { diff --git a/src/supernode/requests.cpp b/src/supernode/requests.cpp index bb75d61e..0fdcf5f8 100644 --- a/src/supernode/requests.cpp +++ b/src/supernode/requests.cpp @@ -16,6 +16,7 @@ #include "supernode/requests/authorize_rta_tx.h" #include "supernode/requests/send_supernode_announce.h" #include "supernode/requests/send_supernode_stake_txs.h" +#include "supernode/requests/blockchain_based_list.h" namespace graft::supernode::request::debug { void __registerDebugRequests(Router& router); } namespace graft::request::system_info { void register_request(Router& router); } @@ -35,6 +36,7 @@ void registerRTARequests(graft::Router &router) registerAuthorizeRtaTxRequests(router); registerSendSupernodeAnnounceRequest(router); registerSendSupernodeStakeTransactionsRequest(router); + registerBlockchainBasedListRequest(router); } void registerWalletApiRequests(graft::Router &router) diff --git a/src/supernode/requests/blockchain_based_list.cpp b/src/supernode/requests/blockchain_based_list.cpp new file mode 100644 index 00000000..b158b9fd --- /dev/null +++ b/src/supernode/requests/blockchain_based_list.cpp @@ -0,0 +1,122 @@ +// Copyright (c) 2018, The Graft Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "supernode/requests/blockchain_based_list.h" +#include "supernode/requestdefines.h" +#include "rta/fullsupernodelist.h" +#include "rta/supernode.h" + +#include +#include + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "supernode.blockchainbasedlistrequest" + +namespace { + static const char* PATH = "/blockchain_based_list"; +} + +namespace graft::supernode::request { + +namespace +{ + +Status blockchainBasedListHandler + (const Router::vars_t& vars, + const graft::Input& input, + graft::Context& ctx, + graft::Output& output) +{ + LOG_PRINT_L1(PATH << " called with payload: " << input.data()); + + boost::shared_ptr fsl = ctx.global.get("fsl", boost::shared_ptr()); + SupernodePtr supernode = ctx.global.get("supernode", SupernodePtr()); + + if (!fsl.get()) { + LOG_ERROR("Internal error. Supernode list object missing"); + return Status::Error; + } + + if (!supernode.get()) { + LOG_ERROR("Internal error. Supernode object missing"); + return Status::Error; + } + + BlockchainBasedListJsonRpcRequest req; + + if (!input.get(req)) + { + // can't parse request + LOG_ERROR("Failed to parse request"); + return Status::Error; + } + + //handle tiers + + FullSupernodeList::SupernodeTierArray tiers; + + for (const BlockchainBasedListTier& tier : req.params.tiers) + { + const std::vector& supernode_descs = tier.supernodes; + + std::vector supernodes; + + supernodes.reserve(supernode_descs.size()); + + for (const BlockchainBasedListTierEntry& supernode_desc : supernode_descs) + { + const std::string& supernode_public_id = supernode_desc.supernode_public_id; + + if (!fsl->exists(supernode_public_id)) + continue; + + SupernodePtr sn = fsl->get(supernode_public_id); + + supernodes.push_back(sn); + } + + tiers.emplace_back(std::move(supernodes)); + } + + fsl->setBlockchainBasedList(req.params.block_number, tiers); + + return Status::Ok; +} + +} + +void registerBlockchainBasedListRequest(graft::Router &router) +{ + Router::Handler3 h3(nullptr, blockchainBasedListHandler, nullptr); + + router.addRoute(PATH, METHOD_POST, h3); + + LOG_PRINT_L0("route " << PATH << " registered"); +} + +} diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 9402c1a0..59e56df4 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -83,16 +83,18 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, std::vector sample; uint64_t height; + std::string payment_id; try { height = stoull(vars.find("height")->second); + payment_id = vars.find("payment_id")->second; } catch(...) { return errorInternalError("invalid input", output); } - const bool ok = fsl->buildAuthSample(height, sample); + const bool ok = fsl->buildAuthSample(height, payment_id, sample); if(!ok) { return errorInternalError("failed to build auth sample", output); @@ -139,7 +141,7 @@ void __registerDebugRequests(Router &router) router.addRoute("/debug/supernode_list/{all:[0-1]}", METHOD_GET, _HANDLER(getSupernodeList)); router.addRoute("/debug/announce", METHOD_POST, _HANDLER(doAnnounce)); router.addRoute("/debug/close_wallets/", METHOD_POST, _HANDLER(closeStakeWallets)); - router.addRoute("/debug/auth_sample/{height:[0-9]+}", METHOD_GET, _HANDLER(getAuthSample)); + router.addRoute("/debug/auth_sample/{height:[0-9]+}/{payment_id:[0-9a-zA-Z]+}", METHOD_GET, _HANDLER(getAuthSample)); } } diff --git a/src/supernode/requests/pay.cpp b/src/supernode/requests/pay.cpp index eae4f2c1..019f733e 100644 --- a/src/supernode/requests/pay.cpp +++ b/src/supernode/requests/pay.cpp @@ -119,7 +119,7 @@ Status handleClientPayRequest(const Router::vars_t& vars, const graft::Input& in } std::vector authSample; - if (!fsl->buildAuthSample(in.BlockNumber, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { + if (!fsl->buildAuthSample(in.BlockNumber, in.PaymentID, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { return errorBuildAuthSample(output); } @@ -209,7 +209,7 @@ Status handleWaitingTxReply(const Router::vars_t& vars, const graft::Input& inpu } std::vector authSample; - if (!fsl->buildAuthSample(payData.BlockNumber, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { + if (!fsl->buildAuthSample(payData.BlockNumber, payData.PaymentID, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { return errorBuildAuthSample(output); } diff --git a/src/supernode/requests/sale.cpp b/src/supernode/requests/sale.cpp index ba29689b..a3d5667f 100644 --- a/src/supernode/requests/sale.cpp +++ b/src/supernode/requests/sale.cpp @@ -86,7 +86,7 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i // generate auth sample std::vector authSample; - if (!fsl->buildAuthSample(data.BlockNumber, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { + if (!fsl->buildAuthSample(data.BlockNumber, payment_id, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { return errorCustomError(MESSAGE_RTA_CANT_BUILD_AUTH_SAMPLE, ERROR_INVALID_PARAMS, output); } diff --git a/src/supernode/requests/sale_details.cpp b/src/supernode/requests/sale_details.cpp index 45ded0b7..89d9d8dd 100644 --- a/src/supernode/requests/sale_details.cpp +++ b/src/supernode/requests/sale_details.cpp @@ -100,7 +100,7 @@ Status handleClientRequest(const Router::vars_t& vars, const graft::Input& input FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, SupernodePtr()); - if (!fsl->buildAuthSample(in.BlockNumber, authSample)) { + if (!fsl->buildAuthSample(in.BlockNumber, in.PaymentID, authSample)) { return errorBuildAuthSample(output); } // we have sale details locally, easy way @@ -290,7 +290,7 @@ Status handleSaleDetailsUnicastRequest(const Router::vars_t& vars, const graft:: << ", payment: " << sdr.PaymentID << ", block: " << sdr.BlockNumber); - if (!fsl->buildAuthSample(sdr.BlockNumber, authSample)) { + if (!fsl->buildAuthSample(sdr.BlockNumber, sdr.PaymentID, authSample)) { LOG_ERROR("failed to build auth sample for block: " << sdr.BlockNumber << ", payment: " << sdr.PaymentID); return sendOkResponseToCryptonode(output); // cryptonode doesn't care about any errors, it's job is only deliver request diff --git a/test/rta_classes_test.cpp b/test/rta_classes_test.cpp index b8f58993..c34f6586 100644 --- a/test/rta_classes_test.cpp +++ b/test/rta_classes_test.cpp @@ -338,8 +338,8 @@ TEST_F(FullSupernodeListTest, buildAuthSample) // test if result is reproducable for (size_t i = 0; i < 100; ++i) { - sn_list.buildAuthSample(10000 + i, auth_sample); - sn_list.buildAuthSample(10000 + i, auth_sample2); + sn_list.buildAuthSample(10000 + i, "aabbccddeeff", auth_sample); + sn_list.buildAuthSample(10000 + i, "aabbccddeeff", auth_sample2); ASSERT_EQ(auth_sample.size(), FullSupernodeList::AUTH_SAMPLE_SIZE); ASSERT_EQ(auth_sample2.size(), FullSupernodeList::AUTH_SAMPLE_SIZE); From 056e529879c5376b81c1ac8891f9110c13cd979a Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Tue, 26 Feb 2019 22:43:55 +0200 Subject: [PATCH 26/85] graftlet_walletAddress is being built with tests only, fixed --- graftlets/CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/graftlets/CMakeLists.txt b/graftlets/CMakeLists.txt index c9ef75dd..c44a564f 100644 --- a/graftlets/CMakeLists.txt +++ b/graftlets/CMakeLists.txt @@ -25,6 +25,14 @@ include_directories( ${PROJECT_SOURCE_DIR}/../modules/libr3/include ) + +add_library(graftlet_walletAddress SHARED + WalletAddress.cpp +) +set_target_properties(graftlet_walletAddress PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/supernode +) + if (OPT_BUILD_TESTS) message("==> Test graftlets included") @@ -36,11 +44,4 @@ if (OPT_BUILD_TESTS) TestGraftlet1.cpp ) - add_library(graftlet_walletAddress SHARED - WalletAddress.cpp - ) - set_target_properties(graftlet_walletAddress PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/supernode - ) endif() - From c9632e572f7bd843de077d209ea07116dbf5da75 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 27 Feb 2019 11:29:32 +0200 Subject: [PATCH 27/85] Update cryptonode --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 6b796e56..af1c1b44 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 6b796e566780b1cbeaafe338d1bc24e26dc1ccef +Subproject commit af1c1b44d4c09fcdb2bb135c6141bc222fa28f69 From 066e3955a5ffecbabbf9dc7dc6dc2c842af7f3d7 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 28 Feb 2019 00:40:11 +0200 Subject: [PATCH 28/85] Blockchain based list communication from cryptonode to supernode --- include/rta/DaemonRpcClient.h | 1 + include/rta/fullsupernodelist.h | 13 ++++++------ modules/cryptonode | 2 +- src/rta/DaemonRpcClient.cpp | 18 +++++++++++++++++ src/rta/fullsupernodelist.cpp | 20 ++++++++++++------- .../requests/blockchain_based_list.cpp | 11 +++------- src/supernode/supernode.cpp | 2 +- 7 files changed, 44 insertions(+), 23 deletions(-) diff --git a/include/rta/DaemonRpcClient.h b/include/rta/DaemonRpcClient.h index 6a11a128..2b72862a 100644 --- a/include/rta/DaemonRpcClient.h +++ b/include/rta/DaemonRpcClient.h @@ -52,6 +52,7 @@ class DaemonRpcClient bool get_height(uint64_t &height); bool get_block_hash(uint64_t height, std::string &hash); bool send_supernode_stake_txs(const char* network_address, const char* address); + bool send_supernode_blockchain_based_list(const char* network_address, const char* address); protected: bool init(const std::string &daemon_address, boost::optional daemon_login); diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index fdbaa96f..abe9062e 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -144,14 +144,14 @@ class FullSupernodeList */ void updateStakeTransactions(const stake_transaction_array& stake_txs); - typedef std::vector SupernodeArray; - typedef std::vector SupernodeTierArray; + typedef std::vector SupernodeIdArray; + typedef std::vector SupernodeIdTierArray; /*! * \brief setBlockchainBasedList - updates full list of supernodes * \return */ - void setBlockchainBasedList(uint64_t block_number, const SupernodeTierArray& tiers); + void setBlockchainBasedList(uint64_t block_number, const SupernodeIdTierArray& tiers); /*! * \brief blockchainBasedListBlockNumber - number of block which blockchain list is built for @@ -163,12 +163,13 @@ class FullSupernodeList * \brief refreshedStakeTransactions - request stake transactions from cryptonode * \return */ - void refreshStakeTransactions(const char* supernode_network_address, const char* supernode_address); + void refreshStakeTransactionsAndBlockchainBasedList(const char* supernode_network_address, const char* supernode_address); private: bool loadWallet(const std::string &wallet_path); void updateStakeTransactionsImpl(); - void selectSupernodes(const std::string& payment_id, const SupernodeArray& src_array, SupernodeArray& dst_array); + typedef std::vector SupernodeArray; + void selectSupernodes(const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array); private: std::unordered_map m_list; @@ -180,7 +181,7 @@ class FullSupernodeList std::unique_ptr m_tp; std::atomic_size_t m_refresh_counter; uint64_t m_blockchain_based_list_block_number; - SupernodeTierArray m_blockchain_based_list; //TODO: lifetime of supernodes, should this be an array of weak pointers? + SupernodeIdTierArray m_blockchain_based_list; }; using FullSupernodeListPtr = boost::shared_ptr; diff --git a/modules/cryptonode b/modules/cryptonode index af1c1b44..b20f1f66 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit af1c1b44d4c09fcdb2bb135c6141bc222fa28f69 +Subproject commit b20f1f66d9d4401cfe29a7514510e4d5e90ca722 diff --git a/src/rta/DaemonRpcClient.cpp b/src/rta/DaemonRpcClient.cpp index 253e555d..4dbbad8e 100644 --- a/src/rta/DaemonRpcClient.cpp +++ b/src/rta/DaemonRpcClient.cpp @@ -190,6 +190,24 @@ bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, cons return true; } +bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_address, const char* address) +{ + epee::json_rpc::request req = AUTO_VAL_INIT(req); + epee::json_rpc::response res = AUTO_VAL_INIT(res); + req.jsonrpc = "2.0"; + req.id = epee::serialization::storage_entry(0); + req.method = "send_supernode_blockchain_based_list"; + req.params.network_address = network_address; + req.params.address = address; + bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); + if (!r) { + LOG_ERROR("/json_rpc/rta/send_supernode_blockchain_based_list error"); + return false; + } + + return true; +} + bool DaemonRpcClient::init(const string &daemon_address, boost::optional daemon_login) { return m_http_client.set_server(daemon_address, daemon_login); diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index d5c32788..2540239b 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -228,7 +228,7 @@ SupernodePtr FullSupernodeList::get(const string &address) const return SupernodePtr(nullptr); } -void FullSupernodeList::selectSupernodes(const std::string& payment_id, const SupernodeArray& src_array, SupernodeArray& dst_array) +void FullSupernodeList::selectSupernodes(const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array) { const char* it = payment_id.c_str(); const size_t supernodes_count = src_array.size(); @@ -254,8 +254,13 @@ void FullSupernodeList::selectSupernodes(const std::string& payment_id, const Su break; //all supernodes have been selected } - size_t supernode_index = (offset + base_index) % supernodes_count; - SupernodePtr supernode = src_array[supernode_index]; + size_t supernode_index = (offset + base_index) % supernodes_count; + auto supernode_it = m_list.find(src_array[supernode_index]); + + if (supernode_it == m_list.end()) + continue; + + SupernodePtr supernode = supernode_it->second; bool already_selected = false; for (const SupernodePtr& supernode_it : dst_array) @@ -295,8 +300,8 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym for (size_t i=0; i writerLock(m_access); diff --git a/src/supernode/requests/blockchain_based_list.cpp b/src/supernode/requests/blockchain_based_list.cpp index b158b9fd..7a48a6bf 100644 --- a/src/supernode/requests/blockchain_based_list.cpp +++ b/src/supernode/requests/blockchain_based_list.cpp @@ -78,13 +78,13 @@ Status blockchainBasedListHandler //handle tiers - FullSupernodeList::SupernodeTierArray tiers; + FullSupernodeList::SupernodeIdTierArray tiers; for (const BlockchainBasedListTier& tier : req.params.tiers) { const std::vector& supernode_descs = tier.supernodes; - std::vector supernodes; + std::vector supernodes; supernodes.reserve(supernode_descs.size()); @@ -92,12 +92,7 @@ Status blockchainBasedListHandler { const std::string& supernode_public_id = supernode_desc.supernode_public_id; - if (!fsl->exists(supernode_public_id)) - continue; - - SupernodePtr sn = fsl->get(supernode_public_id); - - supernodes.push_back(sn); + supernodes.push_back(supernode_public_id); } tiers.emplace_back(std::move(supernodes)); diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index 1be7b15a..0896c866 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -126,7 +126,7 @@ void Supernode::requestStakeTransactions() if (FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr())) { - fsl->refreshStakeTransactions(supernode->networkAddress().c_str(), supernode->walletAddress().c_str()); + fsl->refreshStakeTransactionsAndBlockchainBasedList(supernode->networkAddress().c_str(), supernode->walletAddress().c_str()); } return graft::Status::Stop; From 4bb5ca6f4cd26839626dfbd76351a91b8067f322 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 28 Feb 2019 00:56:10 +0200 Subject: [PATCH 29/85] Mersenne-Twister RNG for auth sample building --- include/rta/fullsupernodelist.h | 5 ++- src/rta/fullsupernodelist.cpp | 72 +++++++++++++-------------------- 2 files changed, 31 insertions(+), 46 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index abe9062e..af353035 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -1,6 +1,8 @@ #ifndef FULLSUPERNODELIST_H #define FULLSUPERNODELIST_H +#include + #include "rta/supernode.h" #include "rta/DaemonRpcClient.h" @@ -169,7 +171,7 @@ class FullSupernodeList bool loadWallet(const std::string &wallet_path); void updateStakeTransactionsImpl(); typedef std::vector SupernodeArray; - void selectSupernodes(const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array); + void selectSupernodes(size_t items_count, const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array); private: std::unordered_map m_list; @@ -182,6 +184,7 @@ class FullSupernodeList std::atomic_size_t m_refresh_counter; uint64_t m_blockchain_based_list_block_number; SupernodeIdTierArray m_blockchain_based_list; + std::mt19937_64 m_rng; }; using FullSupernodeListPtr = boost::shared_ptr; diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 2540239b..e2d06058 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -228,57 +228,30 @@ SupernodePtr FullSupernodeList::get(const string &address) const return SupernodePtr(nullptr); } -void FullSupernodeList::selectSupernodes(const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array) +void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array) { - const char* it = payment_id.c_str(); - const size_t supernodes_count = src_array.size(); + size_t src_array_size = src_array.size(); - for (bool loop=true; loop && it[0] && it[1];) - { - if (*it == '-') - { - it++; - continue; - } - - char buffer[] = {it[0], it[1], 0}; - size_t base_index = strtoul(buffer, nullptr, 16); + if (items_count > src_array_size) + items_count = src_array_size; - it += 2; - - for (size_t offset=0;; offset++) - { - if (offset == supernodes_count) - { - loop = false; - break; //all supernodes have been selected - } - - size_t supernode_index = (offset + base_index) % supernodes_count; - auto supernode_it = m_list.find(src_array[supernode_index]); + for (size_t i=0; isecond; - bool already_selected = false; - - for (const SupernodePtr& supernode_it : dst_array) - { - if (supernode_it == supernode) - { - already_selected = true; - break; - } - } + SupernodePtr supernode = supernode_it->second; + + size_t random_value = m_rng() % (src_array_size - i); - if (already_selected) - continue; + if (random_value >= items_count) + continue; - dst_array.push_back(supernode); + dst_array.push_back(supernode); - break; - } + items_count--; } } @@ -289,7 +262,7 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym std::array tier_supernodes; { - boost::shared_lock readerLock(m_access); + boost::unique_lock writerLock(m_access); if (height != m_blockchain_based_list_block_number) { @@ -298,6 +271,15 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym return false; } + //seed RNG + + std::seed_seq seed(reinterpret_cast(payment_id.c_str()), + reinterpret_cast(payment_id.c_str() + payment_id.size())); + + m_rng.seed(seed); + + //select supernodes for a full supernode list + for (size_t i=0; i Date: Fri, 1 Mar 2019 01:14:31 +0200 Subject: [PATCH 30/85] Supernode public wallet address in blockchain based list --- include/rta/fullsupernodelist.h | 21 ++++++++++++------- .../requests/blockchain_based_list.h | 3 ++- modules/cryptonode | 2 +- src/rta/fullsupernodelist.cpp | 16 +++++++------- .../requests/blockchain_based_list.cpp | 11 ++++++---- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index af353035..101d9f32 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -92,6 +92,8 @@ class FullSupernodeList */ SupernodePtr get(const std::string &address) const; + typedef std::vector supernode_array; + /*! * \brief buildAuthSample - builds auth sample (8 supernodes) for given block height * \param height - block height used to perform selection @@ -99,7 +101,7 @@ class FullSupernodeList * \param out - vector of supernode pointers * \return - true on success */ - bool buildAuthSample(uint64_t height, const std::string& payment_id, std::vector &out); + bool buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out); /*! * \brief items - returns address list of known supernodes @@ -145,15 +147,21 @@ class FullSupernodeList * \return */ void updateStakeTransactions(const stake_transaction_array& stake_txs); + + struct blockchain_based_list_entry + { + std::string supernode_public_id; + std::string supernode_public_address; + }; - typedef std::vector SupernodeIdArray; - typedef std::vector SupernodeIdTierArray; + typedef std::vector blockchain_based_list_tier; + typedef std::vector blockchain_based_list; /*! * \brief setBlockchainBasedList - updates full list of supernodes * \return */ - void setBlockchainBasedList(uint64_t block_number, const SupernodeIdTierArray& tiers); + void setBlockchainBasedList(uint64_t block_number, const blockchain_based_list& tiers); /*! * \brief blockchainBasedListBlockNumber - number of block which blockchain list is built for @@ -170,8 +178,7 @@ class FullSupernodeList private: bool loadWallet(const std::string &wallet_path); void updateStakeTransactionsImpl(); - typedef std::vector SupernodeArray; - void selectSupernodes(size_t items_count, const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array); + void selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); private: std::unordered_map m_list; @@ -183,7 +190,7 @@ class FullSupernodeList std::unique_ptr m_tp; std::atomic_size_t m_refresh_counter; uint64_t m_blockchain_based_list_block_number; - SupernodeIdTierArray m_blockchain_based_list; + blockchain_based_list m_blockchain_based_list; std::mt19937_64 m_rng; }; diff --git a/include/supernode/requests/blockchain_based_list.h b/include/supernode/requests/blockchain_based_list.h index 565d8de4..377be3ea 100644 --- a/include/supernode/requests/blockchain_based_list.h +++ b/include/supernode/requests/blockchain_based_list.h @@ -7,7 +7,8 @@ namespace graft::supernode::request { GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTierEntry, - (std::string, supernode_public_id, std::string()) + (std::string, supernode_public_id, std::string()), + (std::string, supernode_public_address, std::string()) ); GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTier, diff --git a/modules/cryptonode b/modules/cryptonode index b20f1f66..ca26443c 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit b20f1f66d9d4401cfe29a7514510e4d5e90ca722 +Subproject commit ca26443c76f58e17f45219601194da5fdd09c9fc diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index e2d06058..b84bbb2d 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -228,7 +228,7 @@ SupernodePtr FullSupernodeList::get(const string &address) const return SupernodePtr(nullptr); } -void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& payment_id, const SupernodeIdArray& src_array, SupernodeArray& dst_array) +void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array) { size_t src_array_size = src_array.size(); @@ -237,7 +237,7 @@ void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& for (size_t i=0; i &out) +bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out) { MDEBUG("building auth sample for height " << height << " and PaymentID " << payment_id); - std::array tier_supernodes; + std::array tier_supernodes; { boost::unique_lock writerLock(m_access); @@ -282,8 +282,8 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym for (size_t i=0; i writerLock(m_access); diff --git a/src/supernode/requests/blockchain_based_list.cpp b/src/supernode/requests/blockchain_based_list.cpp index 7a48a6bf..7ee64aa9 100644 --- a/src/supernode/requests/blockchain_based_list.cpp +++ b/src/supernode/requests/blockchain_based_list.cpp @@ -78,21 +78,24 @@ Status blockchainBasedListHandler //handle tiers - FullSupernodeList::SupernodeIdTierArray tiers; + FullSupernodeList::blockchain_based_list tiers; for (const BlockchainBasedListTier& tier : req.params.tiers) { const std::vector& supernode_descs = tier.supernodes; - std::vector supernodes; + FullSupernodeList::blockchain_based_list_tier supernodes; supernodes.reserve(supernode_descs.size()); for (const BlockchainBasedListTierEntry& supernode_desc : supernode_descs) { - const std::string& supernode_public_id = supernode_desc.supernode_public_id; + FullSupernodeList::blockchain_based_list_entry entry; - supernodes.push_back(supernode_public_id); + entry.supernode_public_id = supernode_desc.supernode_public_id; + entry.supernode_public_address = supernode_desc.supernode_public_address; + + supernodes.emplace_back(std::move(entry)); } tiers.emplace_back(std::move(supernodes)); From 2972f5bcf9e70fe8b8f6ac9b86d136178e28d750 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 4 Mar 2019 15:42:07 +0200 Subject: [PATCH 31/85] Auth sample building fixes --- src/rta/fullsupernodelist.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index b84bbb2d..40905b81 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -146,7 +146,7 @@ bool FullSupernodeList::add(Supernode *item) bool FullSupernodeList::add(SupernodePtr item) { - if (exists(item->walletAddress())) { + if (exists(item->idKeyAsString())) { LOG_ERROR("item already exists: " << item->walletAddress()); return false; } @@ -237,11 +237,11 @@ void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& for (size_t i=0; isecond; size_t random_value = m_rng() % (src_array_size - i); @@ -280,7 +280,7 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym //select supernodes for a full supernode list - for (size_t i=0; i Date: Thu, 28 Feb 2019 12:20:46 +0300 Subject: [PATCH 32/85] removed libwallet supernodes --- graftlets/WalletAddress.cpp | 154 +------ include/rta/fullsupernodelist.h | 21 +- include/rta/supernode.h | 116 ++--- .../requests/send_supernode_announce.h | 12 +- modules/cryptonode | 2 +- src/rta/DaemonRpcClient.cpp | 8 +- src/rta/fullsupernodelist.cpp | 96 ++-- src/rta/supernode.cpp | 413 ++++++------------ src/supernode/requests/authorize_rta_tx.cpp | 38 +- src/supernode/requests/sale_status.cpp | 5 +- .../requests/send_supernode_announce.cpp | 46 +- src/supernode/supernode.cpp | 19 +- test/rta_classes_test.cpp | 2 + 13 files changed, 307 insertions(+), 625 deletions(-) diff --git a/graftlets/WalletAddress.cpp b/graftlets/WalletAddress.cpp index 4997cbfe..fa32d8bf 100644 --- a/graftlets/WalletAddress.cpp +++ b/graftlets/WalletAddress.cpp @@ -32,6 +32,7 @@ #include "WalletAddress.h" #include "supernode/requestdefines.h" +#include "rta/supernode.h" #include "lib/graft/graft_exception.h" #include "cryptonote_basic/cryptonote_basic_impl.h" #include "cryptonote_protocol/blobdatatype.h" @@ -47,21 +48,13 @@ class WalletAddress: public IGraftlet public: WalletAddress(const char* name) : IGraftlet(name) { } - virtual void initOnce(const graft::CommonOpts& opts) override + virtual void initOnce(const graft::CommonOpts& /*opts*/) override { - makeGetWalletAddressResponse(opts); - REGISTER_ENDPOINT("/dapi/v2.0/cryptonode/getwalletaddress", METHOD_GET | METHOD_POST, WalletAddress, getWalletAddressHandler); } private: graft::Status getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output); - void makeGetWalletAddressResponse(const graft::CommonOpts& opts); - void checkWalletPublicAddress(const graft::CommonOpts& opts); - void prepareIdKeys(const graft::CommonOpts& opts, crypto::public_key& W, crypto::secret_key& w); - bool verifySignature(); - graft::supernode::request::GetWalletAddressResponse m_response; - graft::supernode::request::GetWalletAddressErrorResponse m_errorResponse; }; GRAFTLET_EXPORTS_BEGIN("walletAddress", GRAFTLET_MKVER(1,1)); @@ -70,136 +63,35 @@ GRAFTLET_EXPORTS_END GRAFTLET_PLUGIN_DEFAULT_CHECK_FW_VERSION(GRAFTLET_MKVER(0,3)) -graft::Status WalletAddress::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output) +graft::Status WalletAddress::getWalletAddressHandler(const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, + graft::Output& output) { LOG_PRINT_L2(__FUNCTION__); - assert(ctx.local.getLastStatus() == graft::Status::None); - if(m_response.wallet_public_address.empty()) - { - output.load(m_errorResponse); - return graft::Status::Ok; - } - output.load(m_response); - return graft::Status::Ok; -} - -/*! - * \brief makeGetWalletAddressResponse - fills and signs m_response - */ -void WalletAddress::makeGetWalletAddressResponse(const graft::CommonOpts& opts) -{ - m_errorResponse.testnet = opts.testnet; - - if(opts.wallet_public_address.empty()) return; - checkWalletPublicAddress(opts); - crypto::public_key W; - crypto::secret_key w; - prepareIdKeys(opts, W, w); - - m_response.testnet = opts.testnet; - m_response.wallet_public_address = opts.wallet_public_address; - m_response.id_key = epee::string_tools::pod_to_hex(W); - - crypto::signature sign; - {//sign - std::string data = m_response.wallet_public_address + ":" + m_response.id_key; - crypto::hash hash; - crypto::cn_fast_hash(data.data(), data.size(), hash); - crypto::generate_signature(hash, W, w, sign); + if (ctx.local.getLastStatus() != graft::Status::None) { + graft::supernode::request::GetWalletAddressErrorResponse err; + err.error = string("internal error: wrong status: " + to_string((int)ctx.local.getLastStatus())); + return graft::Status::Error; } - m_response.signature = epee::string_tools::pod_to_hex(sign); - - assert(verifySignature()); -} - -/*! - * \brief verifySignature - only for testing here, the code can be used on the other side - */ -bool WalletAddress::verifySignature() -{ - crypto::public_key W; - bool ok = epee::string_tools::hex_to_pod(m_response.id_key, W); - assert(ok); - - crypto::signature sign; - bool ok1 = epee::string_tools::hex_to_pod(m_response.signature, sign); - assert(ok1); - - std::string data = m_response.wallet_public_address + ":" + m_response.id_key; - crypto::hash hash; - crypto::cn_fast_hash(data.data(), data.size(), hash); - return crypto::check_signature(hash, W, sign); -} - -/*! - * \brief checkWalletPublicAddress - checks that opts.wallet_public_address is valid - * on error throws graft::exit_error exception - */ -void WalletAddress::checkWalletPublicAddress(const graft::CommonOpts& opts) -{ - cryptonote::account_public_address acc = AUTO_VAL_INIT(acc); - if(!cryptonote::get_account_address_from_str(acc, opts.testnet, opts.wallet_public_address)) - { - std::ostringstream oss; - oss << "invalid wallet-public-address '" << opts.wallet_public_address << "'"; - throw graft::exit_error(oss.str()); + graft::SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, graft::SupernodePtr()); + if (!supernode) { + graft::supernode::request::GetWalletAddressErrorResponse err; + err.error = string("supernode was not setup correctly"); + return graft::Status::Error; } -} -/*! - * \brief prepareIdKeys - gets id keys, generates them if required - * on errors throws graft::exit_error exception - */ -void WalletAddress::prepareIdKeys(const graft::CommonOpts& opts, crypto::public_key& W, crypto::secret_key& w) -{ - boost::filesystem::path data_path(opts.data_dir); + graft::supernode::request::GetWalletAddressResponse response; + response.testnet = supernode->testnet(); + response.id_key = supernode->idKeyAsString(); + response.wallet_public_address = supernode->walletAddress(); - boost::filesystem::path wallet_keys_file = data_path / "wallet.keys"; - if (!boost::filesystem::exists(wallet_keys_file)) - { - LOG_PRINT_L0("file '") << wallet_keys_file << "' not found. Generating the keys"; - crypto::generate_keys(W, w); - //save secret key - boost::filesystem::path wallet_keys_file_tmp = wallet_keys_file; - wallet_keys_file_tmp += ".tmp"; - std::string w_str = epee::string_tools::pod_to_hex(w); - bool r = epee::file_io_utils::save_string_to_file(wallet_keys_file_tmp.string(), w_str); - if(!r) - { - std::ostringstream oss; - oss << "Cannot write to file '" << wallet_keys_file_tmp << "'"; - throw graft::exit_error(oss.str()); - } - boost::system::error_code errcode; - boost::filesystem::rename(wallet_keys_file_tmp, wallet_keys_file, errcode); - assert(!errcode); - } - else - { - LOG_PRINT_L1(" Reading wallet keys file '") << wallet_keys_file << "'"; - std::string w_str; - bool r = epee::file_io_utils::load_file_to_string(wallet_keys_file.string(), w_str); - if(!r) - { - std::ostringstream oss; - oss << "Cannot read file '" << wallet_keys_file << "'"; - throw graft::exit_error(oss.str()); - } - - bool ok = epee::string_tools::hex_to_pod(w_str, w); - if(ok) - { - ok = crypto::secret_key_to_public_key(w,W); - } - if(!ok) - { - std::ostringstream oss; - oss << "Corrupted data in the file '" << wallet_keys_file << "'"; - throw graft::exit_error(oss.str()); - } - } + crypto::signature sign; + std::string data = supernode->walletAddress() + ":" + supernode->idKeyAsString(); + supernode->signMessage(data, sign); + response.signature = epee::string_tools::pod_to_hex(sign); + output.load(response); + return graft::Status::Ok; } namespace diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 101d9f32..7d72bc77 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -59,7 +59,7 @@ class FullSupernodeList /*! * \brief remove - removes Supernode from list. closes it's wallet and frees memory - * \param address - supernode address + * \param id - supernode id * \return - true if supernode removed */ bool remove(const std::string &address); @@ -72,25 +72,17 @@ class FullSupernodeList /*! * \brief exists - checks if supernode with given address exists in list - * \param address - supernode address + * \param id - supernode id * \return - true if exists */ - bool exists(const std::string &address) const; - - /*! - * \brief update - updates supernode's key images. this will probably cause stake amount change - * \param address - supernode's address - * \param key_images - list of key images - * \return - true of successfully updated - */ - bool update(const std::string &address, const std::vector &key_images); + bool exists(const std::string &id) const; /*! * \brief get - returns supernode instance (pointer) - * \param address - supernode's address + * \param id - supernode's public id * \return - shared pointer to supernode or empty pointer (nullptr) is no such address */ - SupernodePtr get(const std::string &address) const; + SupernodePtr get(const std::string &id) const; typedef std::vector supernode_array; @@ -176,11 +168,12 @@ class FullSupernodeList void refreshStakeTransactionsAndBlockchainBasedList(const char* supernode_network_address, const char* supernode_address); private: - bool loadWallet(const std::string &wallet_path); + // bool loadWallet(const std::string &wallet_path); void updateStakeTransactionsImpl(); void selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); private: + // key is public id as a string std::unordered_map m_list; stake_transaction_array m_stake_txs; std::string m_daemon_address; diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 945cb8be..fbdaeff4 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -34,24 +34,9 @@ class Supernode static constexpr uint64_t TIER3_STAKE_AMOUNT = config::graft::TIER3_STAKE_AMOUNT; static constexpr uint64_t TIER4_STAKE_AMOUNT = config::graft::TIER4_STAKE_AMOUNT; - /*! - * \brief Supernode - constructs supernode - * \param wallet_path - filename of the existing wallet or new wallet. in case filename doesn't exists, new wallet will be created - * \param wallet_password - wallet's password. wallet_path doesn't exists - this password will be used to protect new wallet; - * \param daemon_address - address of the cryptonode daemon - * \param testnet - testnet flag - * \param seed_language - seed language - */ - Supernode(const std::string &wallet_path, const std::string &wallet_password, const std::string &daemon_address, bool testnet = false, - const std::string &seed_language = std::string()); - ~Supernode(); + Supernode(const std::string &wallet_address, const crypto::public_key &id_key, const std::string &daemon_address, bool testnet = false); - /*! - * \brief setDaemonAddress - setup connection with the cryptonode daemon - * \param address - address in "hostname:port" form - * \return - true on success - */ - bool setDaemonAddress(const std::string &address); + ~Supernode(); /*! * \brief refresh - get latest blocks from the daemon @@ -83,13 +68,6 @@ class Supernode * \return - the tier (1-4) of the supernode or 0 if the verified stake amount is below tier 1 */ uint32_t tier() const; - /*! - * \brief walletBalance - returns wallet balance as seen by the internal wallet; note that this - * can be wrong for a view-only wallet with unverified transactions: you - * typically want to use stakeAmount() instead. - * \return - wallet balance in atomic units - */ - uint64_t walletBalance() const; /*! * \brief walletAddress - returns wallet address as string * \return @@ -102,45 +80,6 @@ class Supernode */ uint64_t daemonHeight() const; - /*! - * \brief exportKeyImages - exports key images - * \param key_images - destination vector - * \return - true on success - */ - bool exportKeyImages(std::vector &key_images) const; - - - /*! - * \brief importKeyImages - imports key images - * \param key_images - source vector - * \param height - output height - * \return - true on success - */ - bool importKeyImages(const std::vector &key_images, uint64_t &height); - - /*! - * \brief createFromViewOnlyWallet - creates new Supernode object, creates underlying read-only stake wallet - * \param path - path to wallet files to be created - * \param account_public_address - public address of read-only wallet - * \param viewkey - private view key - * \param testnet - testnet flag - * \return - pointer to Supernode object on success - */ - static Supernode * createFromViewOnlyWallet(const std::string &path, - const std::string &address, - const crypto::secret_key& viewkey = crypto::secret_key(), bool testnet = false); - - /*! - * \brief load - creates new Supernode object from existing wallet - * \param wallet_path - path to existing wallet file - * \param wallet_password - wallet password - * \param daemon_address - daemon address connection for supernode - * \param testnet - testnet flag - * \param seed_language - seed language - * \return - Supernode pointer on success - */ - static Supernode * load(const std::string &wallet_path, const std::string &wallet_password, const std::string &daemon_address, bool testnet = false, - const std::string &seed_language = std::string()); /*! * \brief updateFromAnnounce - updates supernode from announce (helper to extract signed key images from graft::supernode::request::SupernodeAnnounce) @@ -156,19 +95,12 @@ class Supernode * \param testnet - testnet flag * \return - Supernode pointer on success */ - static Supernode * createFromAnnounce(const std::string &path, - const graft::supernode::request::SupernodeAnnounce& announce, + static Supernode * createFromAnnounce(const graft::supernode::request::SupernodeAnnounce& announce, const std::string &daemon_address, bool testnet); bool prepareAnnounce(graft::supernode::request::SupernodeAnnounce& announce); - /*! - * \brief exportViewkey - exports stake wallet private viewkey - * \return private viewkey - */ - crypto::secret_key exportViewkey() const; - /*! * \brief signMessage - signs message. internally hashes the message and signs the hash * \param msg - input message @@ -185,7 +117,7 @@ class Supernode * \param signature - signer's signature * \return - true if signature valid */ - bool verifySignature(const std::string &msg, const std::string &address, const crypto::signature &signature) const; + bool verifySignature(const std::string &msg, const crypto::public_key &pkey, const crypto::signature &signature) const; /*! * \brief getScoreHash - calculates supernode score (TODO: as 265-bit integer) @@ -194,7 +126,7 @@ class Supernode * \return - true on success */ - bool verifyHash(const crypto::hash &hash, const std::string &address, const crypto::signature &signature) const; + bool verifyHash(const crypto::hash &hash, const crypto::public_key &pkey, const crypto::signature &signature) const; void getScoreHash(const crypto::hash &block_hash, crypto::hash &result) const; @@ -202,6 +134,7 @@ class Supernode std::string networkAddress() const; void setNetworkAddress(const std::string &networkAddress); + /*! * \brief getAmountFromTx - scans given tx for outputs destined to this address * \param tx - transaction object @@ -270,21 +203,42 @@ class Supernode */ void setStakeTransactionUnlockTime(uint64_t unlockTime); + /*! + * \brief loadKeys + * \param filename + * \return + */ + bool loadKeys(const std::string &filename); + + /*! + * \brief initKeys + * \param force + * \return + */ + void initKeys(); + + bool saveKeys(const std::string &filename, bool force = false); + + const crypto::public_key &idKey() const; + const crypto::secret_key &secretKey() const; + std::string idKeyAsString() const; + + private: Supernode(bool testnet = false); private: - using wallet2_ptr = boost::scoped_ptr; - mutable wallet2_ptr m_wallet; - static boost::shared_ptr m_ioservice; - std::string m_network_address; - - std::atomic m_last_update_time; - mutable boost::shared_mutex m_wallet_guard; - + // wallet's address. empty in case 'their' supernode + std::string m_wallet_address; + crypto::public_key m_id_key; + crypto::secret_key m_secret_key; + bool m_has_secret_key = false; + std::atomic m_last_update_time; std::atomic m_stake_amount; std::atomic m_stake_transaction_block_height; std::atomic m_stake_transaction_unlock_time; + bool m_testnet = false; + std::string m_network_address; }; using SupernodePtr = boost::shared_ptr; diff --git a/include/supernode/requests/send_supernode_announce.h b/include/supernode/requests/send_supernode_announce.h index fe1f4351..465edc0c 100644 --- a/include/supernode/requests/send_supernode_announce.h +++ b/include/supernode/requests/send_supernode_announce.h @@ -7,18 +7,10 @@ namespace graft::supernode::request { -GRAFT_DEFINE_IO_STRUCT(SignedKeyImageStr, - (std::string, key_image), - (std::string, signature) - ); - GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeAnnounce, - (std::vector, signed_key_images, std::vector()), - (uint64_t, timestamp, 0), - (std::string, address, std::string()), - (uint64_t, stake_amount, 0), + (std::string, supernode_public_id, std::string()), (uint64_t, height, 0), - (std::string, secret_viewkey, std::string()), + (std::string, signature, std::string()), (std::string, network_address, std::string()) ); diff --git a/modules/cryptonode b/modules/cryptonode index ca26443c..d43a9f94 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit ca26443c76f58e17f45219601194da5fdd09c9fc +Subproject commit d43a9f9473775151b2ac61174f3d699d1744e459 diff --git a/src/rta/DaemonRpcClient.cpp b/src/rta/DaemonRpcClient.cpp index 4dbbad8e..cb5762e8 100644 --- a/src/rta/DaemonRpcClient.cpp +++ b/src/rta/DaemonRpcClient.cpp @@ -172,7 +172,7 @@ bool DaemonRpcClient::get_block_hash(uint64_t height, string &hash) return true; } -bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, const char* address) +bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, const char* id) { epee::json_rpc::request req = AUTO_VAL_INIT(req); epee::json_rpc::response res = AUTO_VAL_INIT(res); @@ -180,7 +180,7 @@ bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, cons req.id = epee::serialization::storage_entry(0); req.method = "send_supernode_stake_txs"; req.params.network_address = network_address; - req.params.address = address; + req.params.supernode_public_id = id; bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); if (!r) { LOG_ERROR("/json_rpc/rta/send_supernode_stake_txs error"); @@ -190,7 +190,7 @@ bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, cons return true; } -bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_address, const char* address) +bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_address, const char* id) { epee::json_rpc::request req = AUTO_VAL_INIT(req); epee::json_rpc::response res = AUTO_VAL_INIT(res); @@ -198,7 +198,7 @@ bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_a req.id = epee::serialization::storage_entry(0); req.method = "send_supernode_blockchain_based_list"; req.params.network_address = network_address; - req.params.address = address; + req.params.supernode_public_id = id; bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); if (!r) { LOG_ERROR("/json_rpc/rta/send_supernode_blockchain_based_list error"); diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 40905b81..53454393 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -152,8 +152,8 @@ bool FullSupernodeList::add(SupernodePtr item) } boost::unique_lock writerLock(m_access); - m_list.insert(std::make_pair(item->walletAddress(), item)); - LOG_PRINT_L1("added supernode: " << item->walletAddress()); + m_list.insert(std::make_pair(item->idKeyAsString(), item)); + LOG_PRINT_L1("added supernode: " << item->idKeyAsString()); LOG_PRINT_L1("list size: " << m_list.size()); updateStakeTransactionsImpl(); return true; @@ -161,12 +161,12 @@ bool FullSupernodeList::add(SupernodePtr item) size_t FullSupernodeList::loadFromDir(const string &base_dir) { - vector wallets = findWallets(base_dir); - size_t result = 0; - LOG_PRINT_L1("found wallets: " << wallets.size()); - for (const auto &wallet_path : wallets) { - loadWallet(wallet_path); - } +// vector wallets = findWallets(base_dir); +// size_t result = 0; +// LOG_PRINT_L1("found wallets: " << wallets.size()); +// for (const auto &wallet_path : wallets) { +// loadWallet(wallet_path); +// } return this->size(); } @@ -174,24 +174,24 @@ size_t FullSupernodeList::loadFromDir(const string &base_dir) size_t FullSupernodeList::loadFromDirThreaded(const string &base_dir, size_t &found_wallets) { - vector wallets = findWallets(base_dir); - LOG_PRINT_L1("found wallets: " << wallets.size()); - found_wallets = wallets.size(); +// vector wallets = findWallets(base_dir); +// LOG_PRINT_L1("found wallets: " << wallets.size()); +// found_wallets = wallets.size(); - utils::ThreadPool tp; +// utils::ThreadPool tp; - for (const auto &wallet_path : wallets) { - tp.enqueue(boost::bind(&FullSupernodeList::loadWallet, this, wallet_path)); - } +// for (const auto &wallet_path : wallets) { +// tp.enqueue(boost::bind(&FullSupernodeList::loadWallet, this, wallet_path)); +// } - tp.run(); +// tp.run(); return this->size(); } -bool FullSupernodeList::remove(const string &address) +bool FullSupernodeList::remove(const string &id) { boost::unique_lock readerLock(m_access); - return m_list.erase(address) > 0; + return m_list.erase(id) > 0; } size_t FullSupernodeList::size() const @@ -200,24 +200,24 @@ size_t FullSupernodeList::size() const return m_list.size(); } -bool FullSupernodeList::exists(const string &address) const +bool FullSupernodeList::exists(const string &id) const { boost::shared_lock readerLock(m_access); - return m_list.find(address) != m_list.end(); + return m_list.find(id) != m_list.end(); } -bool FullSupernodeList::update(const string &address, const vector &key_images) -{ +//bool FullSupernodeList::update(const string &address, const vector &key_images) +//{ - boost::unique_lock writerLock(m_access); - auto it = m_list.find(address); - if (it != m_list.end()) { - uint64_t height = 0; - return it->second->importKeyImages(key_images, height); - } - return false; -} +// boost::unique_lock writerLock(m_access); +// auto it = m_list.find(address); +// if (it != m_list.end()) { +// uint64_t height = 0; +// return it->second->importKeyImages(key_images, height); +// } +// return false; +//} SupernodePtr FullSupernodeList::get(const string &address) const { @@ -380,23 +380,23 @@ size_t FullSupernodeList::refreshedItems() const return m_refresh_counter; } -bool FullSupernodeList::loadWallet(const std::string &wallet_path) -{ - bool result = false; - - MDEBUG("loading wallet from: " << wallet_path); - Supernode * sn = Supernode::load(wallet_path, "", m_daemon_address, m_testnet); - if (sn) { - if (!this->add(sn)) { - LOG_ERROR("Can't add supernode " << sn->walletAddress() << ", already exists"); - delete sn; - } else { - MINFO("Added supernode: " << sn->walletAddress() << ", stake: " << sn->stakeAmount()); - result = true; - } - } - return result; -} +//bool FullSupernodeList::loadWallet(const std::string &wallet_path) +//{ +// bool result = false; + +// MDEBUG("loading wallet from: " << wallet_path); +// Supernode * sn = Supernode::load(wallet_path, "", m_daemon_address, m_testnet); +// if (sn) { +// if (!this->add(sn)) { +// LOG_ERROR("Can't add supernode " << sn->walletAddress() << ", already exists"); +// delete sn; +// } else { +// MINFO("Added supernode: " << sn->walletAddress() << ", stake: " << sn->stakeAmount()); +// result = true; +// } +// } +// return result; +//} void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs) { @@ -431,7 +431,7 @@ void FullSupernodeList::updateStakeTransactionsImpl() for (const stake_transaction& tx : m_stake_txs) { - auto it = m_list.find(tx.supernode_public_address); //TODO: change to public_id + auto it = m_list.find(tx.supernode_public_id); if (it == m_list.end()) continue; diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 166b6534..bd2a16df 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -17,68 +17,31 @@ using namespace std; namespace graft { - -using graft::supernode::request::SignedKeyImageStr; using graft::supernode::request::SupernodeAnnounce; -boost::shared_ptr Supernode::m_ioservice { new boost::asio::io_service() }; #ifndef __cpp_inline_variables constexpr uint64_t Supernode::TIER1_STAKE_AMOUNT, Supernode::TIER2_STAKE_AMOUNT, Supernode::TIER3_STAKE_AMOUNT, Supernode::TIER4_STAKE_AMOUNT; #endif -Supernode::Supernode(const string &wallet_path, const string &wallet_password, const string &daemon_address, bool testnet, - const string &seed_language) - : m_wallet{new tools::wallet2(testnet, false, Supernode::m_ioservice)} +Supernode::Supernode(const string &wallet_address, const crypto::public_key &id_key, const string &daemon_address, bool testnet) + : m_wallet_address(wallet_address) + , m_id_key(id_key) + , m_has_secret_key(false) , m_last_update_time {0} , m_stake_amount() , m_stake_transaction_block_height() , m_stake_transaction_unlock_time() + , m_testnet(testnet) { - bool keys_file_exists; - bool wallet_file_exists; - - tools::wallet2::wallet_exists(wallet_path, keys_file_exists, wallet_file_exists); - - MDEBUG("daemon address: " << daemon_address << ", keys_file_exists: " << boolalpha << keys_file_exists << noboolalpha - << " wallet_file_exists: " << boolalpha << wallet_file_exists << noboolalpha); - - // wallet needs to be initialized with the daemon address first. - // Otherwize, wallet will get wrong "refresh_from_blockheight" value - m_wallet->init(daemon_address); - - // existing wallet, open it - if (keys_file_exists) { - m_wallet->load(wallet_path, wallet_password); - // new wallet, generating it - } else { - if(!seed_language.empty()) - m_wallet->set_seed_language(seed_language); - crypto::secret_key recovery_val, secret_key; - recovery_val = m_wallet->generate(wallet_path, wallet_password, secret_key, false, false); - } - - // new wallet. in case we don't have a connection to a daemon at the moment wallet created - // it may happen wallet get "refresh from block height" parameter in the future - if (!keys_file_exists) { - std::string error; - uint64 daemon_height = m_wallet->get_daemon_blockchain_height(error); - // daemon_height will be 0 in case no daemon - if (daemon_height == 0) - m_wallet->set_refresh_from_block_height(0); - } - m_wallet->store(); - MDEBUG("refresh from block height: " << m_wallet->get_refresh_from_block_height()); MINFO("supernode created: " << "[" << this << "] " << this->walletAddress()); } + Supernode::~Supernode() { LOG_PRINT_L0("destroying supernode: " << "[" << this << "] " << this->walletAddress()); - { - boost::unique_lock writeLock(m_wallet_guard); - m_wallet->store(); - } + } uint64_t Supernode::stakeAmount() const @@ -101,163 +64,22 @@ uint32_t Supernode::tier() const (stake >= TIER4_STAKE_AMOUNT); } -uint64_t Supernode::walletBalance() const -{ - boost::shared_lock readLock(m_wallet_guard); - return m_wallet->balance(); -} - string Supernode::walletAddress() const { - return m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + return m_wallet_address; } uint64_t Supernode::daemonHeight() const { uint64_t result = 0; - std::string err; - boost::shared_lock readLock(m_wallet_guard); - result = m_wallet->get_daemon_blockchain_height(err); - if (!result) { - LOG_ERROR(err); - } return result; } -bool Supernode::exportKeyImages(vector &key_images) const -{ - boost::shared_lock readLock(m_wallet_guard); - try { - key_images = m_wallet->export_key_images(); - return !key_images.empty(); - } catch (const std::exception &e) { - LOG_ERROR("wallet exception: " << e.what()); - return false; - } catch (...) { - LOG_ERROR("unknown exception"); - return false; - } -} - -bool Supernode::importKeyImages(const vector &key_images, uint64_t &height) -{ - uint64_t spent = 0; - uint64_t unspent = 0; - - try - { - // shared_mutex isn't recursive, we need to unlock it before daemonHeight() called - boost::unique_lock writeLock(m_wallet_guard); - m_wallet->import_key_images(key_images, spent, unspent); - m_last_update_time = static_cast(std::time(nullptr)); - } - catch(const std::exception& e) - { - LOG_ERROR("wallet exception: " << e.what()); - return false; - } - catch (...) - { - LOG_ERROR("unknown exception"); - return false; - } - - height = this->daemonHeight(); - return true; -} - -Supernode *Supernode::createFromViewOnlyWallet(const string &path, const string &address, const secret_key &viewkey, bool testnet) -{ - Supernode * result = nullptr; - bool keys_file_exists; - bool wallet_file_exists; - // TODO: password - string password = ""; - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); - - if (keys_file_exists) { - LOG_ERROR("attempting to generate view only wallet, but specified file(s) exist. Exiting to not risk overwriting."); - return result; - } - - cryptonote::account_public_address wallet_addr; - if (!cryptonote::get_account_address_from_str(wallet_addr, testnet, address)) { - LOG_ERROR("Error parsing address"); - return result; - } - - result = new Supernode(testnet); - result->m_wallet->generate(path, password, wallet_addr, viewkey); - return result; -} - -Supernode *Supernode::load(const string &wallet_path, const string &wallet_password, const string &daemon_address, bool testnet, const string &seed_language) -{ - Supernode * sn = nullptr; - try { - sn = new Supernode(wallet_path, wallet_password, daemon_address, testnet); - sn->refresh(); - - if (false/*sn->stakeAmount() < Supernode::TIER1_STAKE_AMOUNT*/) { - LOG_ERROR("wallet " << sn->walletAddress() << " doesn't have enough stake to be supernode: " << sn->stakeAmount()); - delete sn; - return nullptr; - } else { - LOG_PRINT_L1("Loaded supernode: " << sn->walletAddress() << ", stake: " << sn->stakeAmount()); - } - } catch (...) { // wallet exception; TODO: catch specific exception if possible - LOG_ERROR("libwallet exception"); - } - - return sn; -} bool Supernode::updateFromAnnounce(const SupernodeAnnounce &announce) { - // check if address match - MDEBUG("updating supernode from announce: " << announce.address); - if (this->walletAddress() != announce.address) { - LOG_ERROR("wrong address. this address: " << this->walletAddress() << ", announce address: " << announce.address); - return false; - } - - // update wallet's blockchain first - // refresh is protected by mutex - if (!this->refresh()) - return false; - - vector signed_key_images; - - for (const SignedKeyImageStr &skis : announce.signed_key_images) { - crypto::key_image ki; - crypto::signature s; - - if (!epee::string_tools::hex_to_pod(skis.key_image, ki)) { - LOG_ERROR("failed to parse key image: " << skis.key_image); - return false; - } - - if (!epee::string_tools::hex_to_pod(skis.signature, s)) { - LOG_ERROR("failed to parse key signature: " << skis.signature); - return false; - } - signed_key_images.push_back(std::make_pair(ki, s)); - } - - uint64_t height = 0; - if (!importKeyImages(signed_key_images, height)) { - LOG_ERROR("failed to import key images"); - return false; - } - - if (!signed_key_images.empty() && height == 0) { - LOG_ERROR("key images imported but height is 0"); - return false; - } - - // TODO: check self amount vs announced amount - setNetworkAddress(announce.network_address); + //setNetworkAddress(announce.network_address); m_last_update_time = static_cast(std::time(nullptr)); uint64 stake_amount = stakeAmount(); MDEBUG("update from announce done for: " << walletAddress() << @@ -266,143 +88,100 @@ bool Supernode::updateFromAnnounce(const SupernodeAnnounce &announce) return true; } -Supernode *Supernode::createFromAnnounce(const string &path, const SupernodeAnnounce &announce, const std::string &daemon_address, +Supernode *Supernode::createFromAnnounce(const SupernodeAnnounce &announce, const std::string &daemon_address, bool testnet) { - Supernode * result = nullptr; - crypto::secret_key viewkey; - if (!epee::string_tools::hex_to_pod(announce.secret_viewkey, viewkey)) { - LOG_ERROR("Failed to parse secret viewkey from string: " << announce.secret_viewkey); + crypto::public_key id_key; + if (!epee::string_tools::hex_to_pod(announce.supernode_public_id, id_key)) { + MERROR("Failed to parse id key from announce: " << announce.supernode_public_id); return nullptr; } - try { - result = Supernode::createFromViewOnlyWallet(path, announce.address, viewkey, testnet); - // before importing key images, wallet needs to be connected to daemon and syncrhonized - if (result) { - result->setDaemonAddress(daemon_address); - result->updateFromAnnounce(announce); - } - } catch (...) { - LOG_ERROR("wallet exception"); - delete result; - result = nullptr; + crypto::signature sign; + if (!epee::string_tools::hex_to_pod(announce.signature, sign)) { + MERROR("Failed to parse signature from announce: " << announce.signature); + return nullptr; + } + + crypto::hash hash; + string msg = announce.supernode_public_id + to_string(announce.height); + crypto::cn_fast_hash(msg.c_str(), msg.length(), hash); + + + + if (crypto::check_signature(hash, id_key, sign)) { + MERROR("Signature check failed "); + return nullptr; } + + Supernode * result = new Supernode("", id_key, daemon_address, testnet); + // TODO: get stake amount here? return result; } bool Supernode::prepareAnnounce(SupernodeAnnounce &announce) { - { - boost::shared_lock lock(m_wallet_guard); - if (!m_wallet->is_synced()) { - MWARNING("Wallet is not synced"); - return false; - } - - announce.timestamp = time(nullptr); - announce.secret_viewkey = epee::string_tools::pod_to_hex(this->exportViewkey()); - announce.height = m_wallet->get_blockchain_current_height(); - - vector signed_key_images; - if (!exportKeyImages(signed_key_images)) { - LOG_ERROR("Failed to export key images"); - return false; - } - - for (const SignedKeyImage &ski : signed_key_images) { - SignedKeyImageStr skis; - skis.key_image = epee::string_tools::pod_to_hex(ski.first); - skis.signature = epee::string_tools::pod_to_hex(ski.second); - announce.signed_key_images.push_back(std::move(skis)); - } - } + announce.supernode_public_id = this->idKeyAsString(); + announce.height = m_stake_transaction_block_height; - announce.stake_amount = this->stakeAmount(); - announce.address = this->walletAddress(); - announce.network_address = this->networkAddress(); + crypto::signature sign; + if (!signMessage(announce.supernode_public_id + to_string(announce.height), sign)) + return false; + announce.signature = epee::string_tools::pod_to_hex(sign); return true; } -crypto::secret_key Supernode::exportViewkey() const -{ - boost::shared_lock readLock(m_wallet_guard); - return m_wallet->get_account().get_keys().m_view_secret_key; -} bool Supernode::signMessage(const string &msg, crypto::signature &signature) const { - if (m_wallet->watch_only()) { - LOG_ERROR("Attempting to sign with watch-only wallet"); - return false; - } - crypto::hash hash; + crypto::cn_fast_hash(msg.data(), msg.size(), hash); + MDEBUG("signing message: " << msg << ", hash: " << hash); return this->signHash(hash, signature); } bool Supernode::signHash(const crypto::hash &hash, crypto::signature &signature) const { - const cryptonote::account_keys &keys = m_wallet->get_account().get_keys(); - crypto::generate_signature(hash, keys.m_account_address.m_spend_public_key, keys.m_spend_secret_key, signature); + if (!m_has_secret_key) { + LOG_ERROR("Attempting to sign with without private key"); + return false; + } + + crypto::generate_signature(hash, m_id_key, m_secret_key, signature); return true; } -bool Supernode::verifySignature(const string &msg, const string &address, const crypto::signature &signature) const +bool Supernode::verifySignature(const string &msg, const crypto::public_key &pkey, const crypto::signature &signature) const { crypto::hash hash; crypto::cn_fast_hash(msg.data(), msg.size(), hash); - return verifyHash(hash, address, signature); -} - -bool Supernode::verifyHash(const crypto::hash &hash, const string &address, const crypto::signature &signature) const -{ - cryptonote::account_public_address wallet_addr; - if (!cryptonote::get_account_address_from_str(wallet_addr, m_wallet->testnet(), address)) { - LOG_ERROR("Error parsing address"); - return false; - } - return crypto::check_signature(hash, wallet_addr.m_spend_public_key, signature); + return verifyHash(hash, pkey, signature); } - - -bool Supernode::setDaemonAddress(const string &address) +bool Supernode::verifyHash(const crypto::hash &hash, const crypto::public_key &pkey, const crypto::signature &signature) const { - // boost::unique_lock writeLock(m_wallet_guard); - return m_wallet->init(address); + return crypto::check_signature(hash, pkey, signature); } bool Supernode::refresh() { - MDEBUG("about to refresh account: " << this->walletAddress()); - boost::unique_lock writeLock(m_wallet_guard); - try { - m_wallet->refresh(); - m_wallet->rescan_unspent(); - m_wallet->store(); - } catch (...) { - LOG_ERROR("Failed to refresh supernode wallet: " << this->walletAddress()); - return false; - } MDEBUG("account refreshed: " << this->walletAddress()); return true; } bool Supernode::testnet() const { - return m_wallet->testnet(); + return m_testnet; } void Supernode::getScoreHash(const crypto::hash &block_hash, crypto::hash &result) const { - // address wont be changed during object lifetime, not need to lock - cryptonote::blobdata data = m_wallet->get_account().get_public_address_str(testnet()); + cryptonote::blobdata data = epee::string_tools::pod_to_hex(m_id_key); data += epee::string_tools::pod_to_hex(block_hash); crypto::cn_fast_hash(data.c_str(), data.size(), result); } @@ -421,12 +200,13 @@ void Supernode::setNetworkAddress(const string &networkAddress) bool Supernode::getAmountFromTx(const cryptonote::transaction &tx, uint64_t &amount) { - return m_wallet->get_amount_from_tx(tx, amount); + // return m_wallet->get_amount_from_tx(tx, amount); + return false; } bool Supernode::getPaymentIdFromTx(const cryptonote::transaction &tx, string &paymentId) { - return true; + return false; } bool Supernode::validateAddress(const string &address, bool testnet) @@ -437,7 +217,6 @@ bool Supernode::validateAddress(const string &address, bool testnet) int64_t Supernode::lastUpdateTime() const { - return m_last_update_time; } @@ -448,12 +227,7 @@ void Supernode::setLastUpdateTime(int64_t time) bool Supernode::busy() const { - if (m_wallet_guard.try_lock_shared()) { - m_wallet_guard.unlock_shared(); - return false; - } else { - return true; - } + return false; } uint64_t Supernode::stakeTransactionBlockHeight() const @@ -476,13 +250,82 @@ void Supernode::setStakeTransactionUnlockTime(uint64_t unlockTime) m_stake_transaction_unlock_time.store(unlockTime); } -Supernode::Supernode(bool testnet) -: m_wallet{ new tools::wallet2(testnet) } -, m_stake_transaction_block_height() -, m_stake_transaction_unlock_time() +bool Supernode::loadKeys(const string &filename) { + if (!boost::filesystem::exists(filename)) { + MWARNING("failed to load keys from file: " << filename << ", file doesn't exists"); + return false; + } + + MTRACE(" Reading wallet keys file '" << filename << "'"); + std::string key_data; + if (!epee::file_io_utils::load_file_to_string(filename, key_data)) { + MERROR("failed to load keys from file: " << filename << ", read error"); + return false; + } + + if (!epee::string_tools::hex_to_pod(key_data, m_secret_key)) { + MERROR("failed to load keys from file: " << filename << ", parse error"); + return false; + } + + if (!crypto::secret_key_to_public_key(m_secret_key, m_id_key)) { + MERROR("failed to load keys from file: " << filename << ", can't generate public key"); + return false; + } + m_has_secret_key = true; + return true; } + +void graft::Supernode::initKeys() +{ + crypto::generate_keys(m_id_key, m_secret_key); + m_has_secret_key = true; } + +bool Supernode::saveKeys(const string &filename, bool force) +{ + if (boost::filesystem::exists(filename) && !force) { + MWARNING("key file already exists: " << filename << " but overwrite is not forced"); + return false; + } + + //save secret key + boost::filesystem::path wallet_keys_file_tmp = filename; + wallet_keys_file_tmp += ".tmp"; + std::string data = epee::string_tools::pod_to_hex(m_secret_key); + if (!epee::file_io_utils::save_string_to_file(wallet_keys_file_tmp.string(), data)) { + MERROR("Cannot write to file '" << wallet_keys_file_tmp << "'"); + return false; + } + + boost::system::error_code errcode; + boost::filesystem::rename(wallet_keys_file_tmp, filename, errcode); + if (errcode) { + MERROR("Cannot rename '" << wallet_keys_file_tmp.string() << " to '" << filename << "', :" << errcode.message()); + return false; + } + return true; +} + +const public_key &Supernode::idKey() const +{ + return m_id_key; +} + +const secret_key &Supernode::secretKey() const +{ + return m_secret_key; +} + +string Supernode::idKeyAsString() const +{ + return epee::string_tools::pod_to_hex(m_id_key); +} + + +} // namespace graft + diff --git a/src/supernode/requests/authorize_rta_tx.cpp b/src/supernode/requests/authorize_rta_tx.cpp index 8e29006e..363d9a1f 100644 --- a/src/supernode/requests/authorize_rta_tx.cpp +++ b/src/supernode/requests/authorize_rta_tx.cpp @@ -50,7 +50,7 @@ namespace { namespace graft::supernode::request { GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeSignature, - (std::string, address, std::string()), + (std::string, id_key, std::string()), (std::string, result_signature, std::string()), // signarure for tx_id + result (std::string, tx_signature, std::string()) // signature for tx_id only ); @@ -92,21 +92,21 @@ struct RtaAuthResult { std::vector approved; std::vector rejected; - bool alreadyApproved(const std::string &address) + bool alreadyApproved(const std::string &id) { - return contains(approved, address); + return contains(approved, id); } - bool alreadyRejected(const std::string &address) + bool alreadyRejected(const std::string &id) { - return contains(rejected, address); + return contains(rejected, id); } private: - bool contains(const std::vector &v, const std::string &address) + bool contains(const std::vector &v, const std::string &id) { return std::find_if(v.begin(), v.end(), [&](const SupernodeSignature &item) { - return item.address == address; + return item.id_key == id; }) != v.end(); } }; @@ -117,8 +117,8 @@ void putRtaSignaturesToTx(cryptonote::transaction &tx, const std::vector bin_signs; for (const auto &sign : signatures) { cryptonote::rta_signature bin_sign; - if (!cryptonote::get_account_address_from_str(bin_sign.address, testnet, sign.address)) { - LOG_ERROR("error parsing address from string: " << sign.address); + if (!cryptonote::get_account_address_from_str(bin_sign.address, testnet, sign.id_key)) { + LOG_ERROR("error parsing address from string: " << sign.id_key); continue; } epee::string_tools::hex_to_pod(sign.tx_signature, bin_sign.signature); @@ -143,7 +143,7 @@ bool signAuthResponse(AuthorizeRtaTxResponse &arg, const SupernodePtr &supernode epee::string_tools::hex_to_pod(arg.tx_id, tx_id); supernode->signHash(tx_id, sign); arg.signature.tx_signature = epee::string_tools::pod_to_hex(sign); - arg.signature.address = supernode->walletAddress(); + arg.signature.id_key = supernode->idKeyAsString(); return true; } @@ -176,8 +176,10 @@ bool validateAuthResponse(const AuthorizeRtaTxResponse &arg, const SupernodePtr std::string msg = arg.tx_id + ":" + to_string(arg.result); - bool r1 = supernode->verifySignature(msg, arg.signature.address, sign_result); - bool r2 = supernode->verifyHash(tx_id, arg.signature.address, sign_tx_id); + crypto::public_key id_key; + epee::string_tools::hex_to_pod(arg.signature.id_key, id_key); + bool r1 = supernode->verifySignature(msg, id_key, sign_result); + bool r2 = supernode->verifyHash(tx_id, id_key, sign_tx_id); return r1 && r2; } @@ -301,7 +303,7 @@ Status handleTxAuthRequest(const Router::vars_t& vars, const graft::Input& /*inp RTAAuthResult::Approved : RTAAuthResult::Rejected); signAuthResponse(authResponse, supernode); - authResponse.signature.address = supernode->walletAddress(); + authResponse.signature.id_key = supernode->idKeyAsString(); // store tx ctx.global.set(authResponse.tx_id + CONTEXT_KEY_TX_BY_TXID, tx, RTA_TX_TTL); @@ -408,7 +410,7 @@ Status handleRtaAuthResponseMulticast(const Router::vars_t& vars, const graft::I string payment_id = ctx.global.get(ctx_payment_id_key, std::string()); MDEBUG("incoming tx auth response payment: " << payment_id << ", tx_id: " << rtaAuthResp.tx_id - << ", from: " << rtaAuthResp.signature.address + << ", from: " << rtaAuthResp.signature.id_key << ", result: " << int(result)); // store payment id for a logging purposes @@ -430,9 +432,9 @@ Status handleRtaAuthResponseMulticast(const Router::vars_t& vars, const graft::I authResult = ctx.global.get(ctx_tx_to_auth_resp, authResult); } - if (authResult.alreadyApproved(rtaAuthResp.signature.address) - || authResult.alreadyRejected(rtaAuthResp.signature.address)) { - return errorCustomError(string("supernode: ") + rtaAuthResp.signature.address + " already processed", + if (authResult.alreadyApproved(rtaAuthResp.signature.id_key) + || authResult.alreadyRejected(rtaAuthResp.signature.id_key)) { + return errorCustomError(string("supernode: ") + rtaAuthResp.signature.id_key + " already processed", ERROR_ADDRESS_INVALID, output); } @@ -442,7 +444,7 @@ Status handleRtaAuthResponseMulticast(const Router::vars_t& vars, const graft::I authResult.rejected.push_back(rtaAuthResp.signature); } - MDEBUG("rta result accepted from " << rtaAuthResp.signature.address + MDEBUG("rta result accepted from " << rtaAuthResp.signature.id_key << ", payment: " << payment_id); // store result in context diff --git a/src/supernode/requests/sale_status.cpp b/src/supernode/requests/sale_status.cpp index c0f067d4..5b9ac4dd 100644 --- a/src/supernode/requests/sale_status.cpp +++ b/src/supernode/requests/sale_status.cpp @@ -129,7 +129,10 @@ bool checkSaleStatusUpdateSignature(const string &payment_id, int status, const } std::string msg = payment_id + ":" + to_string(status); - return supernode->verifySignature(msg, address, sign); + // TODO: address -> id_key + crypto::public_key id_key; + + return supernode->verifySignature(msg, id_key, sign); } } diff --git a/src/supernode/requests/send_supernode_announce.cpp b/src/supernode/requests/send_supernode_announce.cpp index 02e96d77..b692f8a8 100644 --- a/src/supernode/requests/send_supernode_announce.cpp +++ b/src/supernode/requests/send_supernode_announce.cpp @@ -60,16 +60,17 @@ Status handleSupernodeAnnounce(const Router::vars_t& vars, const graft::Input& i LOG_PRINT_L1(PATH << " called with payload: " << input.data()); // TODO: implement DOS protection, ignore too frequent requests - boost::shared_ptr fsl = ctx.global.get("fsl", boost::shared_ptr()); - SupernodePtr supernode = ctx.global.get("supernode", SupernodePtr()); + boost::shared_ptr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, + boost::shared_ptr()); + SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, SupernodePtr()); - if (!fsl.get()) { + if (!fsl) { LOG_ERROR("Internal error. Supernode list object missing"); return Status::Error; } - if (!supernode.get()) { + if (!supernode) { LOG_ERROR("Internal error. Supernode object missing"); return Status::Error; } @@ -83,42 +84,36 @@ Status handleSupernodeAnnounce(const Router::vars_t& vars, const graft::Input& i // handle announce const SupernodeAnnounce & announce = req.params; - MINFO("received announce for address: " << announce.address); + MINFO("received announce for id: " << announce.supernode_public_id); - if (fsl->exists(announce.address)) { + if (fsl->exists(announce.supernode_public_id)) { // check if supernode currently busy - SupernodePtr sn = fsl->get(announce.address); + SupernodePtr sn = fsl->get(announce.supernode_public_id); if (sn->busy()) { - MWARNING("Unable to update supernode with announce: " << announce.address << ", BUSY"); + MWARNING("Unable to update supernode with announce: " << announce.supernode_public_id << ", BUSY"); return Status::Error; // we don't care about reply here, already replied to the client } - if (!fsl->get(announce.address)->updateFromAnnounce(announce)) { - LOG_ERROR("Failed to update supernode with announce: " << announce.address); + if (!fsl->get(announce.supernode_public_id)->updateFromAnnounce(announce)) { + LOG_ERROR("Failed to update supernode with announce: " << announce.supernode_public_id); return Status::Error; // we don't care about reply here, already replied to the client } } else { - std::string watchonly_wallets_path = ctx.global["watchonly_wallets_path"]; - assert(!watchonly_wallets_path.empty()); - boost::filesystem::path p(watchonly_wallets_path); - p /= announce.address; - std::string wallet_path = p.string(); std::string cryptonode_rpc_address = ctx.global["cryptonode_rpc_address"]; bool testnet = ctx.global["testnet"]; - MINFO("creating wallet in: " << p.string()); - Supernode * s = Supernode::createFromAnnounce(wallet_path, announce, + Supernode * s = Supernode::createFromAnnounce(announce, cryptonode_rpc_address, testnet); if (!s) { - LOG_ERROR("Cant create watch-only supernode wallet for address: " << announce.address); + LOG_ERROR("Cant create watch-only supernode wallet for id: " << announce.supernode_public_id); return Status::Error; } - MINFO("About to add supernode to list [" << s << "]: " << s->walletAddress()); + MINFO("About to add supernode to list [" << s << "]: " << s->idKeyAsString()); if (!fsl->add(s)) { // DO NOT delete "s" here, it will be deleted by smart pointer; - LOG_ERROR("Can't add new supernode to list [" << s << "]" << s->walletAddress()); + LOG_ERROR("Can't add new supernode to list [" << s << "]" << s->idKeyAsString()); } } return Status::Ok; @@ -178,10 +173,10 @@ Status sendAnnounce(const graft::Router::vars_t& vars, const graft::Input& input return graft::Status::Error; } - MDEBUG("about to refresh supernode: " << supernode->walletAddress()); + MDEBUG("about to refresh supernode: " << supernode->idKeyAsString()); if (!supernode->refresh()) { - return errorCustomError(string("failed to refresh supernode: ") + supernode->walletAddress(), + return errorCustomError(string("failed to refresh supernode: ") + supernode->idKeyAsString(), ERROR_INTERNAL_ERROR, output); } @@ -189,7 +184,7 @@ Status sendAnnounce(const graft::Router::vars_t& vars, const graft::Input& input SendSupernodeAnnounceJsonRpcRequest req; if (!supernode->prepareAnnounce(req.params)) { - return errorCustomError(string("failed to prepare announce: ") + supernode->walletAddress(), + return errorCustomError(string("failed to prepare announce: ") + supernode->idKeyAsString(), ERROR_INTERNAL_ERROR, output); } @@ -201,9 +196,8 @@ Status sendAnnounce(const graft::Router::vars_t& vars, const graft::Input& input output.path = "/json_rpc/rta"; // DBG: without cryptonode // output.path = "/dapi/v2.0/send_supernode_announce"; - - MDEBUG("sending announce for address: " << supernode->walletAddress() - << ", stake amount: " << supernode->stakeAmount()); + MDEBUG("sending announce for id: " << supernode->idKeyAsString()); + MDEBUG(output.data()); return graft::Status::Forward; } } diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index 0896c866..7a245941 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -66,8 +66,6 @@ void Supernode::prepareSupernode() } } - - m_configEx.watchonly_wallets_path = watchonly_wallets_path.string(); MINFO("data path: " << data_path.string()); @@ -75,11 +73,20 @@ void Supernode::prepareSupernode() // create supernode instance and put it into global context graft::SupernodePtr supernode = boost::make_shared( - (stake_wallet_path / m_configEx.stake_wallet_name).string(), - "", // TODO + m_configEx.common.wallet_public_address, + crypto::public_key(), m_configEx.cryptonode_rpc_address, m_configEx.common.testnet ); + std::string keyfilename = (data_path / "supernode.keys").string(); + if (!supernode->loadKeys(keyfilename)) { + // supernode is not initialized, generating key + supernode->initKeys(); + if (!supernode->saveKeys(keyfilename)) { + MERROR("Failed to save keys"); + throw std::runtime_error("Failed to save keys"); + } + } supernode->setNetworkAddress(m_configEx.http_address + "/dapi/v2.0"); @@ -90,7 +97,7 @@ void Supernode::prepareSupernode() //put fsl into global context Context ctx(getLooper().getGcm()); - ctx.global["supernode"] = supernode; + ctx.global[CONTEXT_KEY_SUPERNODE] = supernode; ctx.global[CONTEXT_KEY_FULLSUPERNODELIST] = fsl; ctx.global["testnet"] = m_configEx.common.testnet; ctx.global["watchonly_wallets_path"] = m_configEx.watchonly_wallets_path; @@ -126,7 +133,7 @@ void Supernode::requestStakeTransactions() if (FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr())) { - fsl->refreshStakeTransactionsAndBlockchainBasedList(supernode->networkAddress().c_str(), supernode->walletAddress().c_str()); + fsl->refreshStakeTransactionsAndBlockchainBasedList(supernode->networkAddress().c_str(), supernode->idKeyAsString().c_str()); } return graft::Status::Stop; diff --git a/test/rta_classes_test.cpp b/test/rta_classes_test.cpp index c34f6586..e965ac1b 100644 --- a/test/rta_classes_test.cpp +++ b/test/rta_classes_test.cpp @@ -53,6 +53,7 @@ struct SupernodeTest : public ::testing::Test } }; +#if 0 TEST_F(SupernodeTest, open) { MGINFO_YELLOW("*** This test requires running cryptonode RPC on localhost:28881. If not running, test will fail ***"); @@ -544,4 +545,5 @@ TEST_F(FullSupernodeListTest, announce1) ASSERT_TRUE(watch_only_sn2.get() == nullptr); } +#endif From bd46c78da798095fcae91f329ab9ca262ceac7e8 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 28 Feb 2019 23:31:29 +0300 Subject: [PATCH 33/85] fix: Supernode::createFromAnnounce --- include/rta/supernode.h | 4 ++-- src/rta/supernode.cpp | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/rta/supernode.h b/include/rta/supernode.h index fbdaeff4..2553d883 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -117,7 +117,7 @@ class Supernode * \param signature - signer's signature * \return - true if signature valid */ - bool verifySignature(const std::string &msg, const crypto::public_key &pkey, const crypto::signature &signature) const; + static bool verifySignature(const std::string &msg, const crypto::public_key &pkey, const crypto::signature &signature); /*! * \brief getScoreHash - calculates supernode score (TODO: as 265-bit integer) @@ -126,7 +126,7 @@ class Supernode * \return - true on success */ - bool verifyHash(const crypto::hash &hash, const crypto::public_key &pkey, const crypto::signature &signature) const; + static bool verifyHash(const crypto::hash &hash, const crypto::public_key &pkey, const crypto::signature &signature); void getScoreHash(const crypto::hash &block_hash, crypto::hash &result) const; diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index bd2a16df..ce90fa1a 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -104,18 +104,12 @@ Supernode *Supernode::createFromAnnounce(const SupernodeAnnounce &announce, cons return nullptr; } - crypto::hash hash; string msg = announce.supernode_public_id + to_string(announce.height); - crypto::cn_fast_hash(msg.c_str(), msg.length(), hash); - - - - if (crypto::check_signature(hash, id_key, sign)) { + if (!Supernode::verifySignature(msg, id_key, sign)) { MERROR("Signature check failed "); return nullptr; } - Supernode * result = new Supernode("", id_key, daemon_address, testnet); // TODO: get stake amount here? return result; @@ -156,14 +150,14 @@ bool Supernode::signHash(const crypto::hash &hash, crypto::signature &signature) return true; } -bool Supernode::verifySignature(const string &msg, const crypto::public_key &pkey, const crypto::signature &signature) const +bool Supernode::verifySignature(const string &msg, const crypto::public_key &pkey, const crypto::signature &signature) { crypto::hash hash; crypto::cn_fast_hash(msg.data(), msg.size(), hash); return verifyHash(hash, pkey, signature); } -bool Supernode::verifyHash(const crypto::hash &hash, const crypto::public_key &pkey, const crypto::signature &signature) const +bool Supernode::verifyHash(const crypto::hash &hash, const crypto::public_key &pkey, const crypto::signature &signature) { return crypto::check_signature(hash, pkey, signature); } From 1e5b66b1128f3889a93f1ee49190abe762adeac2 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 1 Mar 2019 10:36:57 +0300 Subject: [PATCH 34/85] debug/supernode - added public id field --- src/supernode/requests/debug.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 59e56df4..9bf59728 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -23,6 +23,7 @@ namespace graft::supernode::request::debug { GRAFT_DEFINE_IO_STRUCT(DbSupernode, (std::string, Address), + (std::string, PublicId), (uint64, StakeAmount), (uint64, LastUpdateAge) ); @@ -67,6 +68,7 @@ Status getSupernodeList(const Router::vars_t& vars, const graft::Input& input, DbSupernode dbSupernode; dbSupernode.LastUpdateAge = lastUpdateAge; dbSupernode.Address = sPtr->walletAddress(); + dbSupernode.PublicId = sPtr->idKeyAsString(); dbSupernode.StakeAmount = sPtr->stakeAmount(); resp.result.items.push_back(dbSupernode); } From 57f7e7fc1fa70f8c5d25db1ec613249949f58c94 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 1 Mar 2019 10:57:51 +0300 Subject: [PATCH 35/85] fix: init lastUpdateTime when creating supernode from announce --- src/rta/supernode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index ce90fa1a..fe24c1ed 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -111,6 +111,7 @@ Supernode *Supernode::createFromAnnounce(const SupernodeAnnounce &announce, cons } Supernode * result = new Supernode("", id_key, daemon_address, testnet); + result->setLastUpdateTime(time(nullptr)); // TODO: get stake amount here? return result; } From c8fafa281059f2c89abadbc54e60272cc5fb8770 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 1 Mar 2019 13:01:36 +0300 Subject: [PATCH 36/85] fix: networkAddress restored --- src/rta/supernode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index fe24c1ed..30de233d 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -125,6 +125,7 @@ bool Supernode::prepareAnnounce(SupernodeAnnounce &announce) if (!signMessage(announce.supernode_public_id + to_string(announce.height), sign)) return false; announce.signature = epee::string_tools::pod_to_hex(sign); + announce.network_address = this->networkAddress(); return true; } From b1f4e2e81f4b2c85026047026891e565511dc327 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Sat, 2 Mar 2019 09:28:29 +0200 Subject: [PATCH 37/85] Update cryptonode submodule --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index d43a9f94..c9882ff7 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit d43a9f9473775151b2ac61174f3d699d1744e459 +Subproject commit c9882ff7e331d99ee87bb6b6d89a6357721fef31 From 6e8f8ea2527315f2f0be8fba47d791b9688853fb Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 4 Mar 2019 16:36:59 +0200 Subject: [PATCH 38/85] Update cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index c9882ff7..9c89fa2c 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit c9882ff7e331d99ee87bb6b6d89a6357721fef31 +Subproject commit 9c89fa2c28f2dca8f9eb676b8574abbf249c84f2 From ed55ec03b1d887a10dc2f4ca21eaf9520249210d Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 4 Mar 2019 18:30:43 +0200 Subject: [PATCH 39/85] Update cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 9c89fa2c..eff06383 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 9c89fa2c28f2dca8f9eb676b8574abbf249c84f2 +Subproject commit eff06383766de9f915789faddc2d89493168db9d From 9ca88bea09ef84117df123e6647f9505eecf32e9 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 4 Mar 2019 21:25:25 +0200 Subject: [PATCH 40/85] Add Supernodes to FullSupernodeList accroding to stake transactions --- include/rta/fullsupernodelist.h | 13 +--- include/rta/supernode.h | 24 ++++++- modules/cryptonode | 2 +- src/rta/fullsupernodelist.cpp | 62 ++++++++++++------- src/rta/supernode.cpp | 16 +++++ .../requests/send_supernode_stake_txs.cpp | 7 ++- 6 files changed, 86 insertions(+), 38 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 7d72bc77..99bfd31c 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -123,14 +123,6 @@ class FullSupernodeList */ size_t refreshedItems() const; - struct stake_transaction - { - uint64_t amount = 0; - uint64_t block_height = 0; - uint64_t unlock_time = 0; - std::string supernode_public_id; - std::string supernode_public_address; - }; typedef std::vector stake_transaction_array; /*! @@ -138,7 +130,7 @@ class FullSupernodeList * \param - array of stake transactions * \return */ - void updateStakeTransactions(const stake_transaction_array& stake_txs); + void updateStakeTransactions(const stake_transaction_array& stake_txs, const std::string& cryptonode_rpc_address, bool testnet); struct blockchain_based_list_entry { @@ -169,13 +161,12 @@ class FullSupernodeList private: // bool loadWallet(const std::string &wallet_path); - void updateStakeTransactionsImpl(); + void addImpl(SupernodePtr item); void selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); private: // key is public id as a string std::unordered_map m_list; - stake_transaction_array m_stake_txs; std::string m_daemon_address; bool m_testnet; DaemonRpcClient m_rpc_client; diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 2553d883..2d1347c0 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -21,6 +21,19 @@ namespace cryptonote { namespace graft::supernode::request { struct SupernodeAnnounce; } namespace graft { + +/*! + * \brief Stake transaction description + */ +struct stake_transaction +{ + uint64_t amount = 0; + uint64_t block_height = 0; + uint64_t unlock_time = 0; + std::string supernode_public_id; + std::string supernode_public_address; +}; + /*! * \brief The Supernode class - Representing supernode instance */ @@ -90,7 +103,6 @@ class Supernode /*! * \brief createFromAnnounce - creates new Supernode instance from announce - * \param path - wallet file path * \param announce - announce object * \param testnet - testnet flag * \return - Supernode pointer on success @@ -99,6 +111,16 @@ class Supernode const std::string &daemon_address, bool testnet); + /*! + * \brief createFromStakeTransaction - creates new Supernode instance from stake transaction + * \param transaction - stake transaction + * \param testnet - testnet flag + * \return - Supernode pointer on success + */ + static Supernode * createFromStakeTransaction(const stake_transaction& transaction, + const std::string &daemon_address, + bool testnet); + bool prepareAnnounce(graft::supernode::request::SupernodeAnnounce& announce); /*! diff --git a/modules/cryptonode b/modules/cryptonode index eff06383..6270b214 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit eff06383766de9f915789faddc2d89493168db9d +Subproject commit 6270b214ce1cc4a09751c57c589a2865399b4c30 diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 53454393..153071a6 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -152,11 +152,15 @@ bool FullSupernodeList::add(SupernodePtr item) } boost::unique_lock writerLock(m_access); + addImpl(item); + return true; +} + +void FullSupernodeList::addImpl(SupernodePtr item) +{ m_list.insert(std::make_pair(item->idKeyAsString(), item)); LOG_PRINT_L1("added supernode: " << item->idKeyAsString()); LOG_PRINT_L1("list size: " << m_list.size()); - updateStakeTransactionsImpl(); - return true; } size_t FullSupernodeList::loadFromDir(const string &base_dir) @@ -288,6 +292,8 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym dst_array.reserve(AUTH_SAMPLE_SIZE); selectSupernodes(AUTH_SAMPLE_SIZE, payment_id, src_array, dst_array); + + MDEBUG("..." << dst_array.size() << " supernodes has been selected for tier " << i << " from blockchain based list with " << src_array.size() << " supernodes"); } } @@ -336,6 +342,11 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym MTRACE("auth sample: \n" << auth_sample_str); } + if (out.size() > AUTH_SAMPLE_SIZE) + out.resize(AUTH_SAMPLE_SIZE); + + MDEBUG("..." << out.size() << " supernodes has been selected"); + return out.size() == AUTH_SAMPLE_SIZE; } @@ -398,13 +409,13 @@ size_t FullSupernodeList::refreshedItems() const // return result; //} -void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs) +void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs, const std::string& cryptonode_rpc_address, bool testnet) { - boost::unique_lock writerLock(m_access); + MDEBUG("update stake transactions"); - //reset current stake transactions state + boost::unique_lock writerLock(m_access); - m_stake_txs.clear(); + //clear supernode data for (const std::unordered_map::value_type& sn_desc : m_list) { @@ -418,29 +429,34 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s sn->setStakeTransactionUnlockTime(0); } - //apply new stake transactions state - - m_stake_txs = stake_txs; - - updateStakeTransactionsImpl(); -} - -void FullSupernodeList::updateStakeTransactionsImpl() -{ - MDEBUG("update stake transactions"); + //update supernodes - for (const stake_transaction& tx : m_stake_txs) + for (const stake_transaction& tx : stake_txs) { auto it = m_list.find(tx.supernode_public_id); - if (it == m_list.end()) - continue; + if (it != m_list.end()) + { + SupernodePtr sn = it->second; - SupernodePtr sn = it->second; + sn->setStakeAmount(tx.amount); + sn->setStakeTransactionBlockHeight(tx.block_height); + sn->setStakeTransactionUnlockTime(tx.unlock_time); + } + else + { + SupernodePtr sn (Supernode::createFromStakeTransaction(tx, cryptonode_rpc_address, testnet)); + + if (!sn) + { + LOG_ERROR("Cant create watch-only supernode wallet for id: " << tx.supernode_public_id); + continue; + } + + MINFO("About to add supernode to list [" << sn << "]: " << sn->idKeyAsString()); - sn->setStakeAmount(tx.amount); - sn->setStakeTransactionBlockHeight(tx.block_height); - sn->setStakeTransactionUnlockTime(tx.unlock_time); + addImpl(sn); + } } } diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 30de233d..28ac303f 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -130,7 +130,23 @@ bool Supernode::prepareAnnounce(SupernodeAnnounce &announce) return true; } +Supernode* Supernode::createFromStakeTransaction(const stake_transaction& transaction, const std::string &daemon_address, bool testnet) +{ + crypto::public_key id_key; + if (!epee::string_tools::hex_to_pod(transaction.supernode_public_id, id_key)) { + MERROR("Failed to parse id key from stake transaction: " << transaction.supernode_public_id); + return nullptr; + } + std::unique_ptr result (new Supernode(transaction.supernode_public_address, id_key, daemon_address, testnet)); + + result->setLastUpdateTime(time(nullptr)); + result->setStakeAmount(transaction.amount); + result->setStakeTransactionBlockHeight(transaction.block_height); + result->setStakeTransactionUnlockTime(transaction.unlock_time); + + return result.release(); +} bool Supernode::signMessage(const string &msg, crypto::signature &signature) const { diff --git a/src/supernode/requests/send_supernode_stake_txs.cpp b/src/supernode/requests/send_supernode_stake_txs.cpp index dd273173..625bd150 100644 --- a/src/supernode/requests/send_supernode_stake_txs.cpp +++ b/src/supernode/requests/send_supernode_stake_txs.cpp @@ -84,7 +84,7 @@ Status supernodeStakeTransactionsHandler for (const SupernodeStakeTransaction& src_tx : src_stake_txs) { - FullSupernodeList::stake_transaction dst_tx; + stake_transaction dst_tx; dst_tx.amount = src_tx.amount; dst_tx.block_height = src_tx.block_height; @@ -95,7 +95,10 @@ Status supernodeStakeTransactionsHandler dst_stake_txs.emplace_back(std::move(dst_tx)); } - fsl->updateStakeTransactions(dst_stake_txs); + std::string cryptonode_rpc_address = ctx.global["cryptonode_rpc_address"]; + bool testnet = ctx.global["testnet"]; + + fsl->updateStakeTransactions(dst_stake_txs, cryptonode_rpc_address, testnet); return Status::Ok; } From 4c88954cf65b69500de7f803a53d00a8efe06463 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 4 Mar 2019 23:30:09 +0200 Subject: [PATCH 41/85] Update cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 6270b214..de85b6d7 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 6270b214ce1cc4a09751c57c589a2865399b4c30 +Subproject commit de85b6d7fcde45ef26f64913c7ff52e2583d98d3 From 9d028d8794e1a1bf4d11d252343818d3c5e2e3fe Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Tue, 5 Mar 2019 15:48:59 +0200 Subject: [PATCH 42/85] Cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index de85b6d7..a7237c68 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit de85b6d7fcde45ef26f64913c7ff52e2583d98d3 +Subproject commit a7237c68a985456feba661a35f8397580407c6c8 From f34cfc60709cbf1c376e61bbcca23ae727c879d2 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 5 Mar 2019 16:53:28 +0300 Subject: [PATCH 43/85] fix: generate auth sample for sale request --- include/rta/fullsupernodelist.h | 10 ++++++++- include/rta/supernode.h | 6 ------ src/rta/fullsupernodelist.cpp | 36 ++++++++++++++++----------------- src/rta/supernode.cpp | 6 ------ src/supernode/requests/sale.cpp | 2 +- 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 99bfd31c..8b742d53 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -95,6 +95,8 @@ class FullSupernodeList */ bool buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out); + bool buildAuthSample(const std::string& payment_id, supernode_array &out); + /*! * \brief items - returns address list of known supernodes * \return @@ -159,6 +161,12 @@ class FullSupernodeList */ void refreshStakeTransactionsAndBlockchainBasedList(const char* supernode_network_address, const char* supernode_address); + /*! + * \brief getBlockchainHeight - returns current daemon block height + * \return + */ + uint64_t getBlockchainHeight() const; + private: // bool loadWallet(const std::string &wallet_path); void addImpl(SupernodePtr item); @@ -169,7 +177,7 @@ class FullSupernodeList std::unordered_map m_list; std::string m_daemon_address; bool m_testnet; - DaemonRpcClient m_rpc_client; + mutable DaemonRpcClient m_rpc_client; mutable boost::shared_mutex m_access; std::unique_ptr m_tp; std::atomic_size_t m_refresh_counter; diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 2d1347c0..8f5b313e 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -87,12 +87,6 @@ class Supernode */ std::string walletAddress() const; - /*! - * \brief daemonHeight - returns cryptonode's blockchain height - * \return - */ - uint64_t daemonHeight() const; - /*! * \brief updateFromAnnounce - updates supernode from announce (helper to extract signed key images from graft::supernode::request::SupernodeAnnounce) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 153071a6..51e19d0f 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -264,7 +264,6 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym MDEBUG("building auth sample for height " << height << " and PaymentID " << payment_id); std::array tier_supernodes; - { boost::unique_lock writerLock(m_access); @@ -350,6 +349,11 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym return out.size() == AUTH_SAMPLE_SIZE; } +bool FullSupernodeList::buildAuthSample(const string &payment_id, FullSupernodeList::supernode_array &out) +{ + return buildAuthSample(blockchainBasedListBlockNumber(), payment_id, out); +} + vector FullSupernodeList::items() const { boost::shared_lock readerLock(m_access); @@ -391,24 +395,6 @@ size_t FullSupernodeList::refreshedItems() const return m_refresh_counter; } -//bool FullSupernodeList::loadWallet(const std::string &wallet_path) -//{ -// bool result = false; - -// MDEBUG("loading wallet from: " << wallet_path); -// Supernode * sn = Supernode::load(wallet_path, "", m_daemon_address, m_testnet); -// if (sn) { -// if (!this->add(sn)) { -// LOG_ERROR("Can't add supernode " << sn->walletAddress() << ", already exists"); -// delete sn; -// } else { -// MINFO("Added supernode: " << sn->walletAddress() << ", stake: " << sn->stakeAmount()); -// result = true; -// } -// } -// return result; -//} - void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs, const std::string& cryptonode_rpc_address, bool testnet) { MDEBUG("update stake transactions"); @@ -466,6 +452,13 @@ void FullSupernodeList::refreshStakeTransactionsAndBlockchainBasedList(const cha m_rpc_client.send_supernode_blockchain_based_list(network_address, address); } +uint64_t FullSupernodeList::getBlockchainHeight() const +{ + uint64_t result = 0; + bool ret = m_rpc_client.get_height(result); + return ret ? result : 0; +} + void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const blockchain_based_list& tiers) { boost::unique_lock writerLock(m_access); @@ -480,6 +473,11 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc m_blockchain_based_list_block_number = block_number; } +uint64_t FullSupernodeList::blockchainBasedListBlockNumber() const +{ + return m_blockchain_based_list_block_number; +} + std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { for (size_t i = 0; i < supernodes.size(); ++i) { diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 28ac303f..ac82a788 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -69,12 +69,6 @@ string Supernode::walletAddress() const return m_wallet_address; } -uint64_t Supernode::daemonHeight() const -{ - uint64_t result = 0; - return result; -} - bool Supernode::updateFromAnnounce(const SupernodeAnnounce &announce) { diff --git a/src/supernode/requests/sale.cpp b/src/supernode/requests/sale.cpp index a3d5667f..049145b2 100644 --- a/src/supernode/requests/sale.cpp +++ b/src/supernode/requests/sale.cpp @@ -74,7 +74,7 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); // reply to caller (POS) - SaleData data(in.Address, supernode->daemonHeight(), in.Amount); + SaleData data(in.Address, fsl->blockchainBasedListBlockNumber(), in.Amount); // what needs to be multicasted to auth sample ? // 1. payment_id From 4e9372ceef7168da0be8dd8b8b7547632952fba2 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 5 Mar 2019 17:15:35 +0300 Subject: [PATCH 44/85] fix: address -> id_key --- include/supernode/requests/sale.h | 2 +- include/supernode/requests/sale_details.h | 1 + include/supernode/requests/sale_status.h | 2 +- src/rta/fullsupernodelist.cpp | 6 +++--- src/rta/supernode.cpp | 5 ++--- src/supernode/requestdefines.cpp | 2 +- src/supernode/requests/authorize_rta_tx.cpp | 2 +- src/supernode/requests/debug.cpp | 3 ++- src/supernode/requests/pay.cpp | 4 ++-- src/supernode/requests/sale.cpp | 9 +++------ src/supernode/requests/sale_details.cpp | 17 +++++++++-------- src/supernode/requests/sale_status.cpp | 9 +++++++-- 12 files changed, 33 insertions(+), 29 deletions(-) diff --git a/include/supernode/requests/sale.h b/include/supernode/requests/sale.h index 0c6cb1cb..afabf628 100644 --- a/include/supernode/requests/sale.h +++ b/include/supernode/requests/sale.h @@ -9,7 +9,7 @@ namespace graft::supernode::request { // Sale request payload GRAFT_DEFINE_IO_STRUCT_INITED(SaleRequest, - (std::string, Address, std::string()), + (std::string, IdKey, std::string()), (std::string, SaleDetails, std::string()), (std::string, PaymentID, std::string()), (uint64_t, Amount, 0) diff --git a/include/supernode/requests/sale_details.h b/include/supernode/requests/sale_details.h index d12b0381..856d4b34 100644 --- a/include/supernode/requests/sale_details.h +++ b/include/supernode/requests/sale_details.h @@ -11,6 +11,7 @@ namespace graft::supernode::request { // fee per supernode GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeFee, (std::string, Address, std::string()), + (std::string, IdKey, std::string()), (std::string, Fee, std::string()) ); diff --git a/include/supernode/requests/sale_status.h b/include/supernode/requests/sale_status.h index 1ff49c6a..08ba84eb 100644 --- a/include/supernode/requests/sale_status.h +++ b/include/supernode/requests/sale_status.h @@ -16,7 +16,7 @@ GRAFT_DEFINE_IO_STRUCT(SaleStatusRequest, GRAFT_DEFINE_IO_STRUCT_INITED(UpdateSaleStatusBroadcast, (std::string, PaymentID, std::string()), (int, Status, 0), - (std::string, address, std::string()), // address who updates the status + (std::string, id_key, std::string()), // address who updates the status (std::string, signature, std::string()) // signature who updates the status ); diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 51e19d0f..015682e0 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -147,7 +147,7 @@ bool FullSupernodeList::add(Supernode *item) bool FullSupernodeList::add(SupernodePtr item) { if (exists(item->idKeyAsString())) { - LOG_ERROR("item already exists: " << item->walletAddress()); + LOG_ERROR("item already exists: " << item->idKeyAsString()); return false; } @@ -331,7 +331,7 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym if (VLOG_IS_ON(2)) { std::string auth_sample_str, tier_sample_str; for (const auto &a : out) { - auth_sample_str += a->walletAddress() + "\n"; + auth_sample_str += a->idKeyAsString() + "\n"; } for (size_t i = 0; i < select.size(); i++) { if (i > 0) tier_sample_str += ", "; @@ -481,7 +481,7 @@ uint64_t FullSupernodeList::blockchainBasedListBlockNumber() const std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { for (size_t i = 0; i < supernodes.size(); ++i) { - os << supernodes[i]->walletAddress(); + os << supernodes[i]->idKeyAsString(); if (i < supernodes.size() - 1) os << ", "; } diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index ac82a788..3ee460e7 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -34,14 +34,13 @@ Supernode::Supernode(const string &wallet_address, const crypto::public_key &id_ , m_stake_transaction_unlock_time() , m_testnet(testnet) { - MINFO("supernode created: " << "[" << this << "] " << this->walletAddress()); + MINFO("supernode created: " << "[" << this << "] " << this->walletAddress() << ", " << this->idKeyAsString()); } Supernode::~Supernode() { - LOG_PRINT_L0("destroying supernode: " << "[" << this << "] " << this->walletAddress()); - + LOG_PRINT_L0("destroying supernode: " << "[" << this << "] " << this->walletAddress() << ", " << this->idKeyAsString()); } uint64_t Supernode::stakeAmount() const diff --git a/src/supernode/requestdefines.cpp b/src/supernode/requestdefines.cpp index 5fb57b87..bd1dde33 100644 --- a/src/supernode/requestdefines.cpp +++ b/src/supernode/requestdefines.cpp @@ -128,7 +128,7 @@ void cleanPaySaleData(const std::string& payment_id, Context& ctx) void buildBroadcastSaleStatusOutput(const std::string& payment_id, int status, const SupernodePtr& supernode, Output& output) { UpdateSaleStatusBroadcast ussb; - ussb.address = supernode->walletAddress(); + ussb.id_key = supernode->idKeyAsString(); ussb.Status = status; ussb.PaymentID = payment_id; diff --git a/src/supernode/requests/authorize_rta_tx.cpp b/src/supernode/requests/authorize_rta_tx.cpp index 363d9a1f..dabf299f 100644 --- a/src/supernode/requests/authorize_rta_tx.cpp +++ b/src/supernode/requests/authorize_rta_tx.cpp @@ -294,7 +294,7 @@ Status handleTxAuthRequest(const Router::vars_t& vars, const graft::Input& /*inp // TODO: read payment id from transaction, map tx_id to payment_id MulticastRequestJsonRpc authResponseMulticast; authResponseMulticast.method = "multicast"; - authResponseMulticast.params.sender_address = supernode->walletAddress(); + authResponseMulticast.params.sender_address = supernode->idKeyAsString(); authResponseMulticast.params.receiver_addresses = req.params.receiver_addresses; authResponseMulticast.params.callback_uri = PATH_RESPONSE; AuthorizeRtaTxResponse authResponse; diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 9bf59728..a29da15d 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -17,7 +17,7 @@ #include #undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "supernode.payrequest" +#define MONERO_DEFAULT_LOG_CATEGORY "supernode.debugrequest" namespace graft::supernode::request::debug { @@ -107,6 +107,7 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, { DbSupernode sn; sn.Address = sPtr->walletAddress(); + sn.PublicId = sPtr->idKeyAsString(); sn.StakeAmount = sPtr->stakeAmount(); sn.LastUpdateAge = static_cast(std::time(nullptr)) - sPtr->lastUpdateTime(); resp.result.items.push_back(sn); diff --git a/src/supernode/requests/pay.cpp b/src/supernode/requests/pay.cpp index 019f733e..5b2d4ca5 100644 --- a/src/supernode/requests/pay.cpp +++ b/src/supernode/requests/pay.cpp @@ -65,7 +65,7 @@ Status processAuthorizationRequest(const std::string &tx_hex, const PayRequest & // send multicast to /cryptonode/authorize_rta_tx_request MulticastRequestJsonRpc cryptonode_req; for (const auto & sn : authSample) { - cryptonode_req.params.receiver_addresses.push_back(sn->walletAddress()); + cryptonode_req.params.receiver_addresses.push_back(sn->idKeyAsString()); } Output innerOut; @@ -79,7 +79,7 @@ Status processAuthorizationRequest(const std::string &tx_hex, const PayRequest & cryptonode_req.method = "multicast"; cryptonode_req.params.callback_uri = "/cryptonode/authorize_rta_tx_request"; cryptonode_req.params.data = innerOut.data(); - cryptonode_req.params.sender_address = supernode->walletAddress(); + cryptonode_req.params.sender_address = supernode->idKeyAsString(); // store payment id as we need it to change the sale/pay state in next call ctx.local["payment_id"] = pay_request.PaymentID; // TODO: what is the purpose of PayData? diff --git a/src/supernode/requests/sale.cpp b/src/supernode/requests/sale.cpp index 049145b2..42f45a80 100644 --- a/src/supernode/requests/sale.cpp +++ b/src/supernode/requests/sale.cpp @@ -58,10 +58,7 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i } bool testnet = ctx.global["testnet"]; - if (!Supernode::validateAddress(in.Address, testnet)) - { - return errorInvalidAddress(output); - } + std::string payment_id = in.PaymentID; if (payment_id.empty()) // request comes from POS. @@ -74,7 +71,7 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); // reply to caller (POS) - SaleData data(in.Address, fsl->blockchainBasedListBlockNumber(), in.Amount); + SaleData data(in.IdKey, fsl->blockchainBasedListBlockNumber(), in.Amount); // what needs to be multicasted to auth sample ? // 1. payment_id @@ -113,7 +110,7 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i MulticastRequestJsonRpc cryptonode_req; for (const auto & sn : authSample) { - cryptonode_req.params.receiver_addresses.push_back(sn->walletAddress()); + cryptonode_req.params.receiver_addresses.push_back(sn->idKeyAsString()); } MINFO("processed, payment_id: " << payment_id diff --git a/src/supernode/requests/sale_details.cpp b/src/supernode/requests/sale_details.cpp index 89d9d8dd..dafb82e3 100644 --- a/src/supernode/requests/sale_details.cpp +++ b/src/supernode/requests/sale_details.cpp @@ -46,6 +46,7 @@ bool prepareSaleDetailsResponse(const SaleDetailsRequest &req, graft::Context &c for (const auto &member : authSample) { SupernodeFee snf; snf.Address = member->walletAddress(); + snf.IdKey = member->idKeyAsString(); snf.Fee = std::to_string(total_fee / authSample.size()); resp.AuthSample.push_back(snf); } @@ -126,7 +127,7 @@ Status handleClientRequest(const Router::vars_t& vars, const graft::Input& input // in this case, we MUST have sale details received from multicast if (std::find_if(authSample.begin(), authSample.end(), [&](const SupernodePtr &sn) { - return sn->walletAddress() == supernode->walletAddress(); + return sn->idKeyAsString() == supernode->idKeyAsString(); }) != authSample.end()) { ostringstream oss; oss << authSample; @@ -143,10 +144,10 @@ Status handleClientRequest(const Router::vars_t& vars, const graft::Input& input in.callback_uri = "/cryptonode/callback/sale_details/" + boost::uuids::to_string(ctx.getId()); innerOut.loadT(in); UnicastRequestJsonRpc unicastReq; - unicastReq.params.sender_address = supernode->walletAddress(); + unicastReq.params.sender_address = supernode->idKeyAsString(); size_t maxIndex = authSample.size() - 1; size_t randomIndex = utils::random_number(0, maxIndex); - unicastReq.params.receiver_address = authSample.at(randomIndex)->walletAddress(); + unicastReq.params.receiver_address = authSample.at(randomIndex)->idKeyAsString(); MDEBUG("requesting sale details from remote supernode: " << unicastReq.params.receiver_address << ", for payment: " << in.PaymentID); @@ -204,8 +205,8 @@ Status handleSaleDetailsResponse(const Router::vars_t& vars, const graft::Input& MDEBUG("received sale details from remote supernode: " << unicastReq.sender_address << ", payment: " << payment_id); - if (unicastReq.receiver_address != supernode->walletAddress()) { - string msg = string("wrong receiver address: " + unicastReq.receiver_address + ", expected address: " + supernode->walletAddress()); + if (unicastReq.receiver_address != supernode->idKeyAsString()) { + string msg = string("wrong receiver id: " + unicastReq.receiver_address + ", expected id: " + supernode->idKeyAsString()); LOG_ERROR(msg); return errorInternalError(msg, output); } @@ -266,8 +267,8 @@ Status handleSaleDetailsUnicastRequest(const Router::vars_t& vars, const graft:: UnicastRequest unicastReq = in.params; SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, SupernodePtr()); - if (unicastReq.receiver_address != supernode->walletAddress()) { - string msg = string("wrong receiver address: " + supernode->walletAddress()); + if (unicastReq.receiver_address != supernode->idKeyAsString()) { + string msg = string("wrong receiver id: " + supernode->idKeyAsString()); LOG_ERROR(msg); return sendOkResponseToCryptonode(output); // cryptonode doesn't care about any errors, it's job is only deliver request } @@ -313,7 +314,7 @@ Status handleSaleDetailsUnicastRequest(const Router::vars_t& vars, const graft:: callbackReq.params.data = innerOut.data(); callbackReq.params.callback_uri = sdr.callback_uri; - callbackReq.params.sender_address = supernode->walletAddress(); + callbackReq.params.sender_address = supernode->idKeyAsString(); callbackReq.params.receiver_address = unicastReq.sender_address; callbackReq.method = "unicast"; output.load(callbackReq); diff --git a/src/supernode/requests/sale_status.cpp b/src/supernode/requests/sale_status.cpp index 5b9ac4dd..e9d4513a 100644 --- a/src/supernode/requests/sale_status.cpp +++ b/src/supernode/requests/sale_status.cpp @@ -72,7 +72,7 @@ Status updateSaleStatusHandler(const Router::vars_t& vars, const graft::Input& i MDEBUG("sale status update received for payment: " << ussb.PaymentID); - if (!checkSaleStatusUpdateSignature(ussb.PaymentID, ussb.Status, ussb.address, ussb.signature, supernode)) { + if (!checkSaleStatusUpdateSignature(ussb.PaymentID, ussb.Status, ussb.id_key, ussb.signature, supernode)) { error.code = ERROR_RTA_SIGNATURE_FAILED; error.message = "status update: failed to validate signature for payment: " + ussb.PaymentID; LOG_ERROR(error.message); @@ -119,7 +119,7 @@ string signSaleStatusUpdate(const string &payment_id, int status, const Supernod } -bool checkSaleStatusUpdateSignature(const string &payment_id, int status, const string &address, const string &signature, +bool checkSaleStatusUpdateSignature(const string &payment_id, int status, const string &id_key_, const string &signature, const SupernodePtr &supernode) { crypto::signature sign; @@ -131,6 +131,11 @@ bool checkSaleStatusUpdateSignature(const string &payment_id, int status, const std::string msg = payment_id + ":" + to_string(status); // TODO: address -> id_key crypto::public_key id_key; + if (!epee::string_tools::hex_to_pod(id_key_, id_key)) { + LOG_ERROR("Error parsing id_key: " << id_key_); + return false; + } + return supernode->verifySignature(msg, id_key, sign); } From cf4fd54db0ee73e95ce80659238d32c0e3ecc853 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 5 Mar 2019 18:48:27 +0300 Subject: [PATCH 45/85] debug/auth_sample: height is output, not input --- src/supernode/requests/debug.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index a29da15d..815cb453 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -29,7 +29,8 @@ GRAFT_DEFINE_IO_STRUCT(DbSupernode, ); GRAFT_DEFINE_IO_STRUCT(SupernodeListResponse, - (std::vector, items) + (std::vector, items), + (uint64_t, height) ); GRAFT_DEFINE_JSON_RPC_RESPONSE_RESULT(SupernodeListJsonRpcResult, SupernodeListResponse); @@ -50,6 +51,7 @@ Status getSupernodeList(const Router::vars_t& vars, const graft::Input& input, auto supernodes = fsl->items(); SupernodeListJsonRpcResult resp; + resp.result.height = fsl->blockchainBasedListBlockNumber(); for (auto& sa : supernodes) { auto sPtr = fsl->get(sa); @@ -84,11 +86,10 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); std::vector sample; - uint64_t height; + std::string payment_id; try { - height = stoull(vars.find("height")->second); payment_id = vars.find("payment_id")->second; } catch(...) @@ -96,13 +97,14 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, return errorInternalError("invalid input", output); } - const bool ok = fsl->buildAuthSample(height, payment_id, sample); + const bool ok = fsl->buildAuthSample(fsl->blockchainBasedListBlockNumber(), payment_id, sample); if(!ok) { return errorInternalError("failed to build auth sample", output); } SupernodeListJsonRpcResult resp; + resp.result.height = fsl->blockchainBasedListBlockNumber(); for(auto& sPtr : sample) { DbSupernode sn; @@ -144,7 +146,7 @@ void __registerDebugRequests(Router &router) router.addRoute("/debug/supernode_list/{all:[0-1]}", METHOD_GET, _HANDLER(getSupernodeList)); router.addRoute("/debug/announce", METHOD_POST, _HANDLER(doAnnounce)); router.addRoute("/debug/close_wallets/", METHOD_POST, _HANDLER(closeStakeWallets)); - router.addRoute("/debug/auth_sample/{height:[0-9]+}/{payment_id:[0-9a-zA-Z]+}", METHOD_GET, _HANDLER(getAuthSample)); + router.addRoute("/debug/auth_sample/{payment_id:[0-9a-zA-Z]+}", METHOD_GET, _HANDLER(getAuthSample)); } } From 5c5c3f2b1f55f958b1ae6ba4672886f9a70b0798 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 5 Mar 2019 18:50:12 +0300 Subject: [PATCH 46/85] updated cryptonode submodule --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index a7237c68..ffd131da 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit a7237c68a985456feba661a35f8397580407c6c8 +Subproject commit ffd131da8daf182e8c1718d9aa170a4d591466dc From 33b6dd21592f6c9ca5a347b8c610ce34874c2484 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 5 Mar 2019 20:20:02 +0300 Subject: [PATCH 47/85] version bump --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 4f7b12cd..51b2f6c0 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define GRAFT_SUPERNODE_VERSION_TAG "@VERSIONTAG@" -#define GRAFT_SUPERNODE_VERSION "0.4.1" +#define GRAFT_SUPERNODE_VERSION "0.5.0" #define GRAFT_SUPERNODE_RELEASE_NAME "" #define GRAFT_SUPERNODE_VERSION_FULL GRAFT_SUPERNODE_VERSION "-" GRAFT_SUPERNODE_VERSION_TAG From 6ab95ccf4c76de67af851abc716610261d3fee03 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Tue, 5 Mar 2019 19:31:01 +0200 Subject: [PATCH 48/85] Update cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index ffd131da..af9c55c7 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit ffd131da8daf182e8c1718d9aa170a4d591466dc +Subproject commit af9c55c78125f185bb5f7914e2103d910fdfc4cc From 7a40862d75d411d83ad79c7c30ac826637ff4e70 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 6 Mar 2019 00:31:35 +0200 Subject: [PATCH 49/85] Save several blockchain based lists on supernode --- include/rta/fullsupernodelist.h | 21 ++++--- src/rta/fullsupernodelist.cpp | 63 ++++++++++++++----- .../requests/blockchain_based_list.cpp | 3 +- src/supernode/requests/debug.cpp | 6 +- src/supernode/requests/sale.cpp | 2 +- 5 files changed, 66 insertions(+), 29 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 8b742d53..957d9e8d 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -136,24 +136,25 @@ class FullSupernodeList struct blockchain_based_list_entry { - std::string supernode_public_id; - std::string supernode_public_address; + std::string supernode_public_id; + std::string supernode_public_address; }; typedef std::vector blockchain_based_list_tier; typedef std::vector blockchain_based_list; + typedef std::shared_ptr blockchain_based_list_ptr; /*! * \brief setBlockchainBasedList - updates full list of supernodes * \return */ - void setBlockchainBasedList(uint64_t block_number, const blockchain_based_list& tiers); + void setBlockchainBasedList(uint64_t block_number, const blockchain_based_list_ptr& list); /*! - * \brief blockchainBasedListBlockNumber - number of block which blockchain list is built for + * \brief blockchainBasedListMaxBlockNumber - number of latest block which blockchain list is built for * \return */ - uint64_t blockchainBasedListBlockNumber() const; + uint64_t getBlockchainBasedListMaxBlockNumber() const; /*! * \brief refreshedStakeTransactions - request stake transactions from cryptonode @@ -170,7 +171,11 @@ class FullSupernodeList private: // bool loadWallet(const std::string &wallet_path); void addImpl(SupernodePtr item); - void selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); + void selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); + + typedef std::unordered_map blockchain_based_list_map; + + blockchain_based_list_ptr findBlockchainBasedList(uint64_t block_number) const; private: // key is public id as a string @@ -181,8 +186,8 @@ class FullSupernodeList mutable boost::shared_mutex m_access; std::unique_ptr m_tp; std::atomic_size_t m_refresh_counter; - uint64_t m_blockchain_based_list_block_number; - blockchain_based_list m_blockchain_based_list; + uint64_t m_blockchain_based_list_max_block_number; + blockchain_based_list_map m_blockchain_based_lists; std::mt19937_64 m_rng; }; diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 015682e0..df6b0e62 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -15,6 +15,9 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "supernode.fullsupernodelist" +constexpr size_t BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT = 10; +constexpr size_t BLOCKCHAIN_BASED_LIST_HISTORY_SIZE = 100; + namespace fs = boost::filesystem; using namespace boost::multiprecision; @@ -128,7 +131,7 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_testnet(testnet) , m_rpc_client(daemon_address, "", "") , m_tp(new utils::ThreadPool()) - , m_blockchain_based_list_block_number() + , m_blockchain_based_list_max_block_number() { m_refresh_counter = 0; } @@ -194,7 +197,7 @@ size_t FullSupernodeList::loadFromDirThreaded(const string &base_dir, size_t &fo bool FullSupernodeList::remove(const string &id) { - boost::unique_lock readerLock(m_access); + boost::unique_lock writerLock(m_access); return m_list.erase(id) > 0; } @@ -265,15 +268,17 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym std::array tier_supernodes; { - boost::unique_lock writerLock(m_access); + blockchain_based_list_ptr blockchain_based_list = findBlockchainBasedList(height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT); - if (height != m_blockchain_based_list_block_number) + if (!blockchain_based_list) { - LOG_ERROR("unable to build auth sample for block height " << height << " and PaymentID " - << payment_id << " because of mistmatch with blockchain based list block number " << m_blockchain_based_list_block_number); + LOG_ERROR("unable to build auth sample for block height " << height << ", delay " << BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT << " blocks and PaymentID " + << payment_id << ". Blockchain based list for this block is absent, latest block is " << getBlockchainBasedListMaxBlockNumber()); return false; } + boost::unique_lock writerLock(m_access); + //seed RNG std::seed_seq seed(reinterpret_cast(payment_id.c_str()), @@ -283,9 +288,9 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym //select supernodes for a full supernode list - for (size_t i=0; isize(); i FullSupernodeList::items() const @@ -459,23 +464,49 @@ uint64_t FullSupernodeList::getBlockchainHeight() const return ret ? result : 0; } -void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const blockchain_based_list& tiers) +void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const blockchain_based_list_ptr& list) { boost::unique_lock writerLock(m_access); - if (block_number <= m_blockchain_based_list_block_number) + blockchain_based_list_map::const_iterator it = m_blockchain_based_lists.find(block_number); + + if (it != m_blockchain_based_lists.end()) { - MDEBUG("Blockchain based list is obsolete. Incoming list was built for block " << block_number << ", actual block is " << m_blockchain_based_list_block_number); + MWARNING("Blockchain based list for block " << block_number << " has been already defined"); return; } - m_blockchain_based_list = tiers; - m_blockchain_based_list_block_number = block_number; + m_blockchain_based_lists[block_number] = list; + + if (block_number > m_blockchain_based_list_max_block_number) + m_blockchain_based_list_max_block_number = block_number; + + //flush cache - remove old blockchain based lists + + uint64_t oldest_block_number = m_blockchain_based_list_max_block_number - + BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT - BLOCKCHAIN_BASED_LIST_HISTORY_SIZE; + + for (blockchain_based_list_map::iterator it=m_blockchain_based_lists.begin(); it!=m_blockchain_based_lists.end();) + if (it->first < oldest_block_number) it = m_blockchain_based_lists.erase(it); + else ++it; } -uint64_t FullSupernodeList::blockchainBasedListBlockNumber() const +FullSupernodeList::blockchain_based_list_ptr FullSupernodeList::findBlockchainBasedList(uint64_t block_number) const { - return m_blockchain_based_list_block_number; + boost::shared_lock readerLock(m_access); + + blockchain_based_list_map::const_iterator it = m_blockchain_based_lists.find(block_number); + + if (it == m_blockchain_based_lists.end()) + return blockchain_based_list_ptr(); + + return it->second; +} + +uint64_t FullSupernodeList::getBlockchainBasedListMaxBlockNumber() const +{ + boost::shared_lock readerLock(m_access); + return m_blockchain_based_list_max_block_number; } std::ostream& operator<<(std::ostream& os, const std::vector supernodes) diff --git a/src/supernode/requests/blockchain_based_list.cpp b/src/supernode/requests/blockchain_based_list.cpp index 7ee64aa9..c52e7aca 100644 --- a/src/supernode/requests/blockchain_based_list.cpp +++ b/src/supernode/requests/blockchain_based_list.cpp @@ -101,7 +101,8 @@ Status blockchainBasedListHandler tiers.emplace_back(std::move(supernodes)); } - fsl->setBlockchainBasedList(req.params.block_number, tiers); + fsl->setBlockchainBasedList(req.params.block_number, FullSupernodeList::blockchain_based_list_ptr( + new FullSupernodeList::blockchain_based_list(std::move(tiers)))); return Status::Ok; } diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 815cb453..07f6bf92 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -51,7 +51,7 @@ Status getSupernodeList(const Router::vars_t& vars, const graft::Input& input, auto supernodes = fsl->items(); SupernodeListJsonRpcResult resp; - resp.result.height = fsl->blockchainBasedListBlockNumber(); + resp.result.height = fsl->getBlockchainBasedListMaxBlockNumber(); for (auto& sa : supernodes) { auto sPtr = fsl->get(sa); @@ -97,14 +97,14 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, return errorInternalError("invalid input", output); } - const bool ok = fsl->buildAuthSample(fsl->blockchainBasedListBlockNumber(), payment_id, sample); + const bool ok = fsl->buildAuthSample(fsl->getBlockchainBasedListMaxBlockNumber(), payment_id, sample); if(!ok) { return errorInternalError("failed to build auth sample", output); } SupernodeListJsonRpcResult resp; - resp.result.height = fsl->blockchainBasedListBlockNumber(); + resp.result.height = fsl->getBlockchainBasedListMaxBlockNumber(); for(auto& sPtr : sample) { DbSupernode sn; diff --git a/src/supernode/requests/sale.cpp b/src/supernode/requests/sale.cpp index 42f45a80..2bde8a64 100644 --- a/src/supernode/requests/sale.cpp +++ b/src/supernode/requests/sale.cpp @@ -71,7 +71,7 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); // reply to caller (POS) - SaleData data(in.IdKey, fsl->blockchainBasedListBlockNumber(), in.Amount); + SaleData data(in.IdKey, fsl->getBlockchainBasedListMaxBlockNumber(), in.Amount); // what needs to be multicasted to auth sample ? // 1. payment_id From 8105f6ab885e8bab4277639de8281bf4e821c1be Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Wed, 6 Mar 2019 12:29:29 +0300 Subject: [PATCH 50/85] Update cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index af9c55c7..4fe282e6 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit af9c55c78125f185bb5f7914e2103d910fdfc4cc +Subproject commit 4fe282e6a2cd41dd180810447efc539333aa30ac From 1de296ce1f31cd70d0e75c78cf0ed3c6a23128de Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 7 Mar 2019 00:22:04 +0100 Subject: [PATCH 51/85] Override blockchain based lists --- src/rta/fullsupernodelist.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index df6b0e62..58d57603 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -472,7 +472,8 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc if (it != m_blockchain_based_lists.end()) { - MWARNING("Blockchain based list for block " << block_number << " has been already defined"); + MWARNING("Overriding blockchain based list for block " << block_number); + it->second = list; return; } From 30e77dcf8a8f6f1e1886fe03f4215743729097ab Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 7 Mar 2019 00:32:25 +0100 Subject: [PATCH 52/85] Link getBlockchainBasedListMaxBlockNumber() in buildAuthSample and resp.result.height --- src/supernode/requests/debug.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 07f6bf92..37dc7602 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -97,14 +97,15 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, return errorInternalError("invalid input", output); } - const bool ok = fsl->buildAuthSample(fsl->getBlockchainBasedListMaxBlockNumber(), payment_id, sample); + SupernodeListJsonRpcResult resp; + resp.result.height = fsl->getBlockchainBasedListMaxBlockNumber(); + + const bool ok = fsl->buildAuthSample(resp.result.height, payment_id, sample); if(!ok) { return errorInternalError("failed to build auth sample", output); } - SupernodeListJsonRpcResult resp; - resp.result.height = fsl->getBlockchainBasedListMaxBlockNumber(); for(auto& sPtr : sample) { DbSupernode sn; From 2cf6af837646c00e7ff941bb8c2921155ec90f3a Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 7 Mar 2019 03:02:23 +0300 Subject: [PATCH 53/85] fix: const_iterator -> iterator --- src/rta/fullsupernodelist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 58d57603..81ef7e14 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -468,7 +468,7 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc { boost::unique_lock writerLock(m_access); - blockchain_based_list_map::const_iterator it = m_blockchain_based_lists.find(block_number); + blockchain_based_list_map::iterator it = m_blockchain_based_lists.find(block_number); if (it != m_blockchain_based_lists.end()) { From 70a5c2bf21e96d341d2a4faf504df05ee350810a Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 7 Mar 2019 03:43:52 +0300 Subject: [PATCH 54/85] updated cryptonode submodule --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 4fe282e6..8d2584ab 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 4fe282e6a2cd41dd180810447efc539333aa30ac +Subproject commit 8d2584ab773cfbd5328245f4111499e0b4886e61 From 5827658f2d3a3d7eb0c619e3eb0d5f2ee979f465 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 7 Mar 2019 14:03:49 +0100 Subject: [PATCH 55/85] Fix issue with stake trasactions update delay --- include/rta/fullsupernodelist.h | 12 ++++++++++++ src/rta/fullsupernodelist.cpp | 18 ++++++++++++++++++ src/supernode/supernode.cpp | 5 ++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 957d9e8d..d3c935e4 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -168,6 +168,16 @@ class FullSupernodeList */ uint64_t getBlockchainHeight() const; + /*! + * \brief isStakeTransactionsReceived - returns true if stake transactions have been received + */ + bool isStakeTransactionsReceived() const; + + /*! + * \brief isBlockchainBasedListReceived - returns true if blockchain based list has been received + */ + bool isBlockchainBasedListReceived() const; + private: // bool loadWallet(const std::string &wallet_path); void addImpl(SupernodePtr item); @@ -189,6 +199,8 @@ class FullSupernodeList uint64_t m_blockchain_based_list_max_block_number; blockchain_based_list_map m_blockchain_based_lists; std::mt19937_64 m_rng; + bool m_stake_transactions_received; + bool m_blockchain_based_list_received; }; using FullSupernodeListPtr = boost::shared_ptr; diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 81ef7e14..dbf1718e 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -132,6 +132,8 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_rpc_client(daemon_address, "", "") , m_tp(new utils::ThreadPool()) , m_blockchain_based_list_max_block_number() + , m_stake_transactions_received() + , m_blockchain_based_list_received() { m_refresh_counter = 0; } @@ -449,6 +451,8 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s addImpl(sn); } } + + m_stake_transactions_received = true; } void FullSupernodeList::refreshStakeTransactionsAndBlockchainBasedList(const char* network_address, const char* address) @@ -477,6 +481,8 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc return; } + m_blockchain_based_list_received = true; + m_blockchain_based_lists[block_number] = list; if (block_number > m_blockchain_based_list_max_block_number) @@ -510,6 +516,18 @@ uint64_t FullSupernodeList::getBlockchainBasedListMaxBlockNumber() const return m_blockchain_based_list_max_block_number; } +bool FullSupernodeList::isStakeTransactionsReceived() const +{ + boost::shared_lock readerLock(m_access); + return m_stake_transactions_received; +} + +bool FullSupernodeList::isBlockchainBasedListReceived() const +{ + boost::shared_lock readerLock(m_access); + return m_blockchain_based_list_received; +} + std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { for (size_t i = 0; i < supernodes.size(); ++i) { diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index 7a245941..1bdf179d 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -133,10 +133,13 @@ void Supernode::requestStakeTransactions() if (FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr())) { + if (fsl->isStakeTransactionsReceived() && fsl->isBlockchainBasedListReceived()) + return graft::Status::Stop; + fsl->refreshStakeTransactionsAndBlockchainBasedList(supernode->networkAddress().c_str(), supernode->idKeyAsString().c_str()); } - return graft::Status::Stop; + return graft::Status::Ok; }; static const size_t STAKE_TRANSACTIONS_REQUEST_DELAY_MS = 1000; From 6fde1fe98dd5c13df5498350d6623b8be2b45366 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Thu, 7 Mar 2019 16:35:47 +0100 Subject: [PATCH 56/85] Additional logging for auth sample debugging --- include/rta/fullsupernodelist.h | 2 +- src/rta/fullsupernodelist.cpp | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index d3c935e4..54bbe341 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -181,7 +181,7 @@ class FullSupernodeList private: // bool loadWallet(const std::string &wallet_path); void addImpl(SupernodePtr item); - void selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); + bool selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array); typedef std::unordered_map blockchain_based_list_map; diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index dbf1718e..bb47ce0e 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -237,7 +237,7 @@ SupernodePtr FullSupernodeList::get(const string &address) const return SupernodePtr(nullptr); } -void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array) +bool FullSupernodeList::selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array) { size_t src_array_size = src_array.size(); @@ -249,24 +249,35 @@ void FullSupernodeList::selectSupernodes(size_t items_count, const std::string& auto supernode_it = m_list.find(src_array[i].supernode_public_id); if (supernode_it == m_list.end()) - continue; + { + LOG_ERROR("attempt to select unknown supernode " << src_array[i].supernode_public_id); + return false; + } SupernodePtr supernode = supernode_it->second; - size_t random_value = m_rng() % (src_array_size - i); + size_t random_value = m_rng(); + + MDEBUG(".....select random value " << random_value << " with clamp to " << (src_array_size - i) << " items; result is " << (random_value % (src_array_size - i))); + + random_value %= src_array_size - i; if (random_value >= items_count) continue; + MDEBUG(".....supernode " << src_array[i].supernode_public_id << " has been selected"); + dst_array.push_back(supernode); items_count--; } + + return true; } bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out) { - MDEBUG("building auth sample for height " << height << " and PaymentID " << payment_id); + MDEBUG("building auth sample for height " << height << " and PaymentID '" << payment_id << "'"); std::array tier_supernodes; { @@ -297,7 +308,11 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym dst_array.reserve(AUTH_SAMPLE_SIZE); - selectSupernodes(AUTH_SAMPLE_SIZE, payment_id, src_array, dst_array); + if (!selectSupernodes(AUTH_SAMPLE_SIZE, payment_id, src_array, dst_array)) + { + LOG_ERROR("unable to select supernodes for auth sample"); + return false; + } MDEBUG("..." << dst_array.size() << " supernodes has been selected for tier " << i << " from blockchain based list with " << src_array.size() << " supernodes"); } From d75fc759668d9b8c22d307d6aee883c341e513c4 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Fri, 8 Mar 2019 02:05:12 +0100 Subject: [PATCH 57/85] Add temporary debug output for auth sample building. Aggregate supernode RTA attributes (block_number, unlock_time, stake amount) from several stake transactions --- src/rta/fullsupernodelist.cpp | 64 +++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index bb47ce0e..b2562d28 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -258,7 +258,7 @@ bool FullSupernodeList::selectSupernodes(size_t items_count, const std::string& size_t random_value = m_rng(); - MDEBUG(".....select random value " << random_value << " with clamp to " << (src_array_size - i) << " items; result is " << (random_value % (src_array_size - i))); + MDEBUG(".....select random value " << random_value << " items count is " << items_count << " with clamp to " << (src_array_size - i) << " items; result is " << (random_value % (src_array_size - i))); random_value %= src_array_size - i; @@ -277,15 +277,17 @@ bool FullSupernodeList::selectSupernodes(size_t items_count, const std::string& bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out) { - MDEBUG("building auth sample for height " << height << " and PaymentID '" << payment_id << "'"); + uint64_t blockchain_based_list_height = height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT; + + MDEBUG("building auth sample for height " << height << "(blockchain_based_list_height=" << blockchain_based_list_height << ") and PaymentID '" << payment_id << "'"); std::array tier_supernodes; { - blockchain_based_list_ptr blockchain_based_list = findBlockchainBasedList(height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT); + blockchain_based_list_ptr blockchain_based_list = findBlockchainBasedList(blockchain_based_list_height); if (!blockchain_based_list) { - LOG_ERROR("unable to build auth sample for block height " << height << ", delay " << BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT << " blocks and PaymentID " + LOG_ERROR("unable to build auth sample for block height " << height << " (blockchain_based_list_height=" << blockchain_based_list_height << ") and PaymentID " << payment_id << ". Blockchain based list for this block is absent, latest block is " << getBlockchainBasedListMaxBlockNumber()); return false; } @@ -301,6 +303,17 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym //select supernodes for a full supernode list + MDEBUG("use blockchain based list for height " << blockchain_based_list_height << " (" << blockchain_based_list.get() << ")"); + int t = 0; + for (const blockchain_based_list_tier& l : *blockchain_based_list) + { + MDEBUG("...tier #" << t); + int j=0; + for (const blockchain_based_list_entry& e : l) + MDEBUG(".....[" << j++ << "]=" << e.supernode_public_id); + t++; + } + for (size_t i=0, tiers_count=blockchain_based_list->size(); isecond; - sn->setStakeAmount(tx.amount); - sn->setStakeTransactionBlockHeight(tx.block_height); - sn->setStakeTransactionUnlockTime(tx.unlock_time); + //aggregate stake transaction fields for supernode + + if (tx.amount) + { + sn->setStakeAmount(sn->stakeAmount() + tx.amount); + + //find intersection of stake transaction intervals + + uint64_t min_block_height = sn->stakeTransactionBlockHeight(), + max_block_height = min_block_height + sn->stakeTransactionUnlockTime(), + min_tx_block_height = tx.block_height, + max_tx_block_height = min_tx_block_height + tx.unlock_time; + + if (min_tx_block_height > min_block_height) + min_block_height = min_tx_block_height; + + if (max_tx_block_height < max_block_height) + max_block_height = max_tx_block_height; + + if (max_block_height <= min_block_height) + { + sn->setStakeAmount(0); + + max_block_height = min_block_height; + } + + sn->setStakeTransactionBlockHeight(min_block_height); + sn->setStakeTransactionUnlockTime(max_block_height - min_block_height); + } } else { @@ -487,6 +526,17 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc { boost::unique_lock writerLock(m_access); + MDEBUG("update blockchain based list for height " << block_number << " (" << list.get() << ")"); + int t = 0; + for (const blockchain_based_list_tier& l : *list) + { + MDEBUG("...tier #" << t); + int j=0; + for (const blockchain_based_list_entry& e : l) + MDEBUG(".....[" << j++ << "]=" << e.supernode_public_id); + t++; + } + blockchain_based_list_map::iterator it = m_blockchain_based_lists.find(block_number); if (it != m_blockchain_based_lists.end()) From d4071f124fc3875592038b4f5c639c597d5d88d5 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Fri, 8 Mar 2019 02:05:52 +0100 Subject: [PATCH 58/85] Update cryptonode --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 8d2584ab..7a0e7316 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 8d2584ab773cfbd5328245f4111499e0b4886e61 +Subproject commit 7a0e73165a4c7e50f4ef3faa089115b1c50c832e From 04730e91139e231da56a6712fc4628f022d46af8 Mon Sep 17 00:00:00 2001 From: Alexander Suprunenko Date: Fri, 8 Mar 2019 10:27:58 +0200 Subject: [PATCH 59/85] wallet-public-address cannot be empty. --- src/supernode/supernode.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index 1bdf179d..c8432d7d 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -7,6 +7,7 @@ #include "supernode/requests/send_supernode_announce.h" #include "rta/supernode.h" #include "rta/fullsupernodelist.h" +#include "lib/graft/graft_exception.h" #include @@ -41,6 +42,11 @@ bool Supernode::initConfigOption(int argc, const char** argv, ConfigOpts& config m_configEx.stake_wallet_refresh_interval_ms = server_conf.get("stake-wallet-refresh-interval-ms", consts::DEFAULT_STAKE_WALLET_REFRESH_INTERFAL_MS); m_configEx.stake_wallet_refresh_interval_random_factor = server_conf.get("stake-wallet-refresh-interval-random-factor", 0); + + if(m_configEx.common.wallet_public_address.empty()) + { + throw graft::exit_error("Configuration parameter 'wallet-public-address' cannot be empty."); + } return res; } From c37e247ead593dd629f87ec35ba80776afce0d72 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 8 Mar 2019 19:50:23 +0300 Subject: [PATCH 60/85] fix: announce handling - check for empty id --- src/rta/supernode.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 3ee460e7..439b552d 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -85,6 +85,11 @@ Supernode *Supernode::createFromAnnounce(const SupernodeAnnounce &announce, cons bool testnet) { + if (announce.supernode_public_id.empty()) { + MERROR("Empty public id"); + return nullptr; + } + crypto::public_key id_key; if (!epee::string_tools::hex_to_pod(announce.supernode_public_id, id_key)) { MERROR("Failed to parse id key from announce: " << announce.supernode_public_id); From 29bce07973dd1f769cac7412da0c336c1b5d0c5c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 8 Mar 2019 20:16:56 +0300 Subject: [PATCH 61/85] Supernode::createFromAnnounce, Supernode::updateFromAnnounce refactored --- include/rta/supernode.h | 2 ++ src/rta/supernode.cpp | 52 ++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 8f5b313e..90e2b145 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -242,6 +242,8 @@ class Supernode private: Supernode(bool testnet = false); + static bool validateAnnounce(const graft::supernode::request::SupernodeAnnounce& announce, crypto::public_key &id_key); + private: // wallet's address. empty in case 'their' supernode diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 439b552d..4633bfa3 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -73,7 +73,11 @@ bool Supernode::updateFromAnnounce(const SupernodeAnnounce &announce) { // check if address match //setNetworkAddress(announce.network_address); - m_last_update_time = static_cast(std::time(nullptr)); + crypto::public_key id_key; + if (!Supernode::validateAnnounce(announce, id_key)) + return false; + + setLastUpdateTime(std::time(nullptr)); uint64 stake_amount = stakeAmount(); MDEBUG("update from announce done for: " << walletAddress() << "; last update time updated to: " << m_last_update_time << @@ -85,28 +89,9 @@ Supernode *Supernode::createFromAnnounce(const SupernodeAnnounce &announce, cons bool testnet) { - if (announce.supernode_public_id.empty()) { - MERROR("Empty public id"); - return nullptr; - } - crypto::public_key id_key; - if (!epee::string_tools::hex_to_pod(announce.supernode_public_id, id_key)) { - MERROR("Failed to parse id key from announce: " << announce.supernode_public_id); - return nullptr; - } - - crypto::signature sign; - if (!epee::string_tools::hex_to_pod(announce.signature, sign)) { - MERROR("Failed to parse signature from announce: " << announce.signature); - return nullptr; - } - - string msg = announce.supernode_public_id + to_string(announce.height); - if (!Supernode::verifySignature(msg, id_key, sign)) { - MERROR("Signature check failed "); + if (!Supernode::validateAnnounce(announce, id_key)) return nullptr; - } Supernode * result = new Supernode("", id_key, daemon_address, testnet); result->setLastUpdateTime(time(nullptr)); @@ -336,6 +321,31 @@ string Supernode::idKeyAsString() const return epee::string_tools::pod_to_hex(m_id_key); } +bool Supernode::validateAnnounce(const SupernodeAnnounce& announce, crypto::public_key &id_key) +{ + if (announce.supernode_public_id.empty()) { + MERROR("Empty public id"); + return false; + } + + if (!epee::string_tools::hex_to_pod(announce.supernode_public_id, id_key)) { + MERROR("Failed to parse id key from announce: " << announce.supernode_public_id); + return false; + } + + crypto::signature sign; + if (!epee::string_tools::hex_to_pod(announce.signature, sign)) { + MERROR("Failed to parse signature from announce: " << announce.signature); + return false; + } + + string msg = announce.supernode_public_id + to_string(announce.height); + if (!Supernode::verifySignature(msg, id_key, sign)) { + MERROR("Signature check failed "); + return false; + } + return true; +} } // namespace graft From d63cf25da7b6b6d56539eb41771da65c52cb2404 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Fri, 8 Mar 2019 19:26:03 +0100 Subject: [PATCH 62/85] Fix issue with zero stake amount for self supernode --- src/rta/fullsupernodelist.cpp | 43 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index b2562d28..a198e0e3 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -464,30 +464,39 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s if (tx.amount) { - sn->setStakeAmount(sn->stakeAmount() + tx.amount); + if (sn->stakeAmount()) + { + sn->setStakeAmount(sn->stakeAmount() + tx.amount); - //find intersection of stake transaction intervals + //find intersection of stake transaction intervals - uint64_t min_block_height = sn->stakeTransactionBlockHeight(), - max_block_height = min_block_height + sn->stakeTransactionUnlockTime(), - min_tx_block_height = tx.block_height, - max_tx_block_height = min_tx_block_height + tx.unlock_time; + uint64_t min_block_height = sn->stakeTransactionBlockHeight(), + max_block_height = min_block_height + sn->stakeTransactionUnlockTime(), + min_tx_block_height = tx.block_height, + max_tx_block_height = min_tx_block_height + tx.unlock_time; - if (min_tx_block_height > min_block_height) - min_block_height = min_tx_block_height; + if (min_tx_block_height > min_block_height) + min_block_height = min_tx_block_height; - if (max_tx_block_height < max_block_height) - max_block_height = max_tx_block_height; + if (max_tx_block_height < max_block_height) + max_block_height = max_tx_block_height; - if (max_block_height <= min_block_height) - { - sn->setStakeAmount(0); + if (max_block_height <= min_block_height) + { + sn->setStakeAmount(0); - max_block_height = min_block_height; - } + max_block_height = min_block_height; + } - sn->setStakeTransactionBlockHeight(min_block_height); - sn->setStakeTransactionUnlockTime(max_block_height - min_block_height); + sn->setStakeTransactionBlockHeight(min_block_height); + sn->setStakeTransactionUnlockTime(max_block_height - min_block_height); + } + else + { + sn->setStakeAmount(tx.amount); + sn->setStakeTransactionBlockHeight(tx.block_height); + sn->setStakeTransactionUnlockTime(tx.unlock_time); + } } } else From d98729c1b537e0e32fa7fd9fabc648a1f9a5b7bd Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Sat, 9 Mar 2019 01:22:43 +0100 Subject: [PATCH 63/85] Add periodic batch blockchain based list update --- include/rta/DaemonRpcClient.h | 2 +- include/rta/fullsupernodelist.h | 16 +++------- include/supernode/supernode.h | 1 - modules/cryptonode | 2 +- src/rta/DaemonRpcClient.cpp | 3 +- src/rta/fullsupernodelist.cpp | 56 +++++++++++++++++++-------------- src/supernode/supernode.cpp | 44 +++++++++++--------------- 7 files changed, 60 insertions(+), 64 deletions(-) diff --git a/include/rta/DaemonRpcClient.h b/include/rta/DaemonRpcClient.h index 2b72862a..5a4de310 100644 --- a/include/rta/DaemonRpcClient.h +++ b/include/rta/DaemonRpcClient.h @@ -52,7 +52,7 @@ class DaemonRpcClient bool get_height(uint64_t &height); bool get_block_hash(uint64_t height, std::string &hash); bool send_supernode_stake_txs(const char* network_address, const char* address); - bool send_supernode_blockchain_based_list(const char* network_address, const char* address); + bool send_supernode_blockchain_based_list(const char* network_address, const char* address, uint64_t last_received_block_height); protected: bool init(const std::string &daemon_address, boost::optional daemon_login); diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 54bbe341..9857a2d4 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -157,10 +157,10 @@ class FullSupernodeList uint64_t getBlockchainBasedListMaxBlockNumber() const; /*! - * \brief refreshedStakeTransactions - request stake transactions from cryptonode + * \brief synchronizeWithCryptonode - synchronize with cryptonode * \return */ - void refreshStakeTransactionsAndBlockchainBasedList(const char* supernode_network_address, const char* supernode_address); + void synchronizeWithCryptonode(const char* supernode_network_address, const char* supernode_address); /*! * \brief getBlockchainHeight - returns current daemon block height @@ -168,16 +168,6 @@ class FullSupernodeList */ uint64_t getBlockchainHeight() const; - /*! - * \brief isStakeTransactionsReceived - returns true if stake transactions have been received - */ - bool isStakeTransactionsReceived() const; - - /*! - * \brief isBlockchainBasedListReceived - returns true if blockchain based list has been received - */ - bool isBlockchainBasedListReceived() const; - private: // bool loadWallet(const std::string &wallet_path); void addImpl(SupernodePtr item); @@ -201,6 +191,8 @@ class FullSupernodeList std::mt19937_64 m_rng; bool m_stake_transactions_received; bool m_blockchain_based_list_received; + boost::posix_time::ptime m_last_recv_stake_txs; + boost::posix_time::ptime m_last_recv_blockchain_based_list; }; using FullSupernodeListPtr = boost::shared_ptr; diff --git a/include/supernode/supernode.h b/include/supernode/supernode.h index 4833b7ec..a99af49b 100644 --- a/include/supernode/supernode.h +++ b/include/supernode/supernode.h @@ -22,7 +22,6 @@ class Supernode : public GraftServer void setHttpRouters(ConnectionManager& httpcm); void setCoapRouters(ConnectionManager& coapcm); void loadStakeWallets(); - void requestStakeTransactions(); ConfigOptsEx m_configEx; protected: diff --git a/modules/cryptonode b/modules/cryptonode index 7a0e7316..af5fe0e3 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 7a0e73165a4c7e50f4ef3faa089115b1c50c832e +Subproject commit af5fe0e36e4e7ec7bf1c6b5f1f8976fee82c7e07 diff --git a/src/rta/DaemonRpcClient.cpp b/src/rta/DaemonRpcClient.cpp index cb5762e8..a7b018df 100644 --- a/src/rta/DaemonRpcClient.cpp +++ b/src/rta/DaemonRpcClient.cpp @@ -190,7 +190,7 @@ bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, cons return true; } -bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_address, const char* id) +bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_address, const char* id, uint64_t last_received_block_height) { epee::json_rpc::request req = AUTO_VAL_INIT(req); epee::json_rpc::response res = AUTO_VAL_INIT(res); @@ -199,6 +199,7 @@ bool DaemonRpcClient::send_supernode_blockchain_based_list(const char* network_a req.method = "send_supernode_blockchain_based_list"; req.params.network_address = network_address; req.params.supernode_public_id = id; + req.params.last_received_block_height = last_received_block_height; bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); if (!r) { LOG_ERROR("/json_rpc/rta/send_supernode_blockchain_based_list error"); diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index a198e0e3..6b245fda 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -15,8 +15,9 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "supernode.fullsupernodelist" -constexpr size_t BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT = 10; -constexpr size_t BLOCKCHAIN_BASED_LIST_HISTORY_SIZE = 100; +constexpr size_t STAKE_TRANSACTIONS_RECV_TIMEOUT_SECONDS = 600; +constexpr size_t BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS = 180; +constexpr size_t BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT = 10; namespace fs = boost::filesystem; using namespace boost::multiprecision; @@ -132,8 +133,8 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_rpc_client(daemon_address, "", "") , m_tp(new utils::ThreadPool()) , m_blockchain_based_list_max_block_number() - , m_stake_transactions_received() - , m_blockchain_based_list_received() + , m_last_recv_stake_txs(boost::date_time::not_a_date_time) + , m_last_recv_blockchain_based_list(boost::date_time::not_a_date_time) { m_refresh_counter = 0; } @@ -515,13 +516,35 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s } } - m_stake_transactions_received = true; + m_last_recv_stake_txs = boost::posix_time::second_clock::local_time(); } -void FullSupernodeList::refreshStakeTransactionsAndBlockchainBasedList(const char* network_address, const char* address) +namespace { - m_rpc_client.send_supernode_stake_txs(network_address, address); - m_rpc_client.send_supernode_blockchain_based_list(network_address, address); + +bool is_timeout_expired(const boost::posix_time::ptime& last_recv_time, size_t timeout_seconds) +{ + if (last_recv_time.is_not_a_date_time()) + return true; + + boost::posix_time::time_duration duration = boost::posix_time::second_clock::local_time() - last_recv_time; + + return duration > boost::posix_time::seconds(timeout_seconds); +} + +} + +void FullSupernodeList::synchronizeWithCryptonode(const char* network_address, const char* address) +{ + if (is_timeout_expired(m_last_recv_stake_txs, STAKE_TRANSACTIONS_RECV_TIMEOUT_SECONDS)) + { + m_rpc_client.send_supernode_stake_txs(network_address, address); + } + + if (is_timeout_expired(m_last_recv_blockchain_based_list, BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS)) + { + m_rpc_client.send_supernode_blockchain_based_list(network_address, address, m_blockchain_based_list_max_block_number); + } } uint64_t FullSupernodeList::getBlockchainHeight() const @@ -555,7 +578,7 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc return; } - m_blockchain_based_list_received = true; + m_last_recv_blockchain_based_list = boost::posix_time::second_clock::local_time(); m_blockchain_based_lists[block_number] = list; @@ -564,8 +587,7 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc //flush cache - remove old blockchain based lists - uint64_t oldest_block_number = m_blockchain_based_list_max_block_number - - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT - BLOCKCHAIN_BASED_LIST_HISTORY_SIZE; + uint64_t oldest_block_number = m_blockchain_based_list_max_block_number - config::graft::SUPERNODE_HISTORY_SIZE; for (blockchain_based_list_map::iterator it=m_blockchain_based_lists.begin(); it!=m_blockchain_based_lists.end();) if (it->first < oldest_block_number) it = m_blockchain_based_lists.erase(it); @@ -590,18 +612,6 @@ uint64_t FullSupernodeList::getBlockchainBasedListMaxBlockNumber() const return m_blockchain_based_list_max_block_number; } -bool FullSupernodeList::isStakeTransactionsReceived() const -{ - boost::shared_lock readerLock(m_access); - return m_stake_transactions_received; -} - -bool FullSupernodeList::isBlockchainBasedListReceived() const -{ - boost::shared_lock readerLock(m_access); - return m_blockchain_based_list_received; -} - std::ostream& operator<<(std::ostream& os, const std::vector supernodes) { for (size_t i = 0; i < supernodes.size(); ++i) { diff --git a/src/supernode/supernode.cpp b/src/supernode/supernode.cpp index c8432d7d..3b59540e 100644 --- a/src/supernode/supernode.cpp +++ b/src/supernode/supernode.cpp @@ -122,12 +122,24 @@ void Supernode::initMisc(ConfigOpts& configOpts) auto deferred_task = [duration, this] () { std::this_thread::sleep_for(duration); this->loadStakeWallets(); }; std::thread t(deferred_task); t.detach(); - - requestStakeTransactions(); } -void Supernode::requestStakeTransactions() +void Supernode::startSupernodePeriodicTasks() { + // update supernode every interval_ms + + if (m_configEx.stake_wallet_refresh_interval_ms > 0) { + size_t initial_interval_ms = 1000; + getLooper().addPeriodicTask( + graft::Router::Handler3(nullptr, graft::supernode::request::sendAnnounce, nullptr), + std::chrono::milliseconds(m_configEx.stake_wallet_refresh_interval_ms), + std::chrono::milliseconds(initial_interval_ms), + m_configEx.stake_wallet_refresh_interval_random_factor + ); + } + + // sync with cryptonode + auto handler = [](const graft::Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, graft::Output& output)->graft::Status { graft::SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, graft::SupernodePtr(nullptr)); @@ -139,38 +151,20 @@ void Supernode::requestStakeTransactions() if (FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr())) { - if (fsl->isStakeTransactionsReceived() && fsl->isBlockchainBasedListReceived()) - return graft::Status::Stop; - - fsl->refreshStakeTransactionsAndBlockchainBasedList(supernode->networkAddress().c_str(), supernode->idKeyAsString().c_str()); + fsl->synchronizeWithCryptonode(supernode->networkAddress().c_str(), supernode->idKeyAsString().c_str()); } return graft::Status::Ok; }; - static const size_t STAKE_TRANSACTIONS_REQUEST_DELAY_MS = 1000; + static const size_t CRYPTONODE_SYNCHRONIZATION_PERIOD_MS = 1000; - getConnectionBase().getLooper().addPeriodicTask( + getConnectionBase().getLooper().addPeriodicTask( graft::Router::Handler3(nullptr, handler, nullptr), - std::chrono::milliseconds(STAKE_TRANSACTIONS_REQUEST_DELAY_MS) + std::chrono::milliseconds(CRYPTONODE_SYNCHRONIZATION_PERIOD_MS) ); } -void Supernode::startSupernodePeriodicTasks() -{ - // update supernode every interval_ms - - if (m_configEx.stake_wallet_refresh_interval_ms > 0) { - size_t initial_interval_ms = 1000; - getLooper().addPeriodicTask( - graft::Router::Handler3(nullptr, graft::supernode::request::sendAnnounce, nullptr), - std::chrono::milliseconds(m_configEx.stake_wallet_refresh_interval_ms), - std::chrono::milliseconds(initial_interval_ms), - m_configEx.stake_wallet_refresh_interval_random_factor - ); - } -} - void Supernode::setHttpRouters(ConnectionManager& httpcm) { using namespace graft::supernode::request; From b2aa26ab83c610eea4f37426a8735604f7ff5cfc Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Sun, 10 Mar 2019 01:42:30 +0100 Subject: [PATCH 64/85] Use supernode aggregated stakes instead of stake transactions --- CMakeLists.txt | 2 +- include/rta/DaemonRpcClient.h | 4 +- include/rta/fullsupernodelist.h | 12 ++- include/rta/supernode.h | 44 +++++----- .../requests/send_supernode_stake_txs.h | 32 -------- .../requests/send_supernode_stakes.h | 31 +++++++ modules/cryptonode | 2 +- src/rta/DaemonRpcClient.cpp | 10 +-- src/rta/fullsupernodelist.cpp | 81 ++++++------------- src/rta/supernode.cpp | 36 ++++----- src/supernode/requests.cpp | 4 +- ...take_txs.cpp => send_supernode_stakes.cpp} | 41 +++++----- 12 files changed, 131 insertions(+), 168 deletions(-) delete mode 100644 include/supernode/requests/send_supernode_stake_txs.h create mode 100644 include/supernode/requests/send_supernode_stakes.h rename src/supernode/requests/{send_supernode_stake_txs.cpp => send_supernode_stakes.cpp} (71%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec3c09db..56b3ac66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,7 +280,7 @@ add_library(supernode_common STATIC ${PROJECT_SOURCE_DIR}/src/supernode/requests/sale_status.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_raw_tx.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_announce.cpp - ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_stake_txs.cpp + ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_supernode_stakes.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/send_transfer.cpp ${PROJECT_SOURCE_DIR}/src/supernode/requests/blockchain_based_list.cpp ${PROJECT_SOURCE_DIR}/src/rta/DaemonRpcClient.cpp diff --git a/include/rta/DaemonRpcClient.h b/include/rta/DaemonRpcClient.h index 5a4de310..a9c92f61 100644 --- a/include/rta/DaemonRpcClient.h +++ b/include/rta/DaemonRpcClient.h @@ -51,17 +51,15 @@ class DaemonRpcClient bool get_tx(const std::string &hash_str, cryptonote::transaction &out_tx, uint64_t &block_num, bool &mined); bool get_height(uint64_t &height); bool get_block_hash(uint64_t height, std::string &hash); - bool send_supernode_stake_txs(const char* network_address, const char* address); + bool send_supernode_stakes(const char* network_address, const char* address); bool send_supernode_blockchain_based_list(const char* network_address, const char* address, uint64_t last_received_block_height); protected: bool init(const std::string &daemon_address, boost::optional daemon_login); - private: epee::net_utils::http::http_simple_client m_http_client; std::chrono::seconds m_rpc_timeout; - }; } diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 9857a2d4..cc395166 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -125,14 +125,14 @@ class FullSupernodeList */ size_t refreshedItems() const; - typedef std::vector stake_transaction_array; + typedef std::vector supernode_stake_array; /*! - * \brief updateStakeTransactions - update stake transactions - * \param - array of stake transactions + * \brief updateStakes - update stakes + * \param - array of stakes * \return */ - void updateStakeTransactions(const stake_transaction_array& stake_txs, const std::string& cryptonode_rpc_address, bool testnet); + void updateStakes(const supernode_stake_array& stakes, const std::string& cryptonode_rpc_address, bool testnet); struct blockchain_based_list_entry { @@ -189,9 +189,7 @@ class FullSupernodeList uint64_t m_blockchain_based_list_max_block_number; blockchain_based_list_map m_blockchain_based_lists; std::mt19937_64 m_rng; - bool m_stake_transactions_received; - bool m_blockchain_based_list_received; - boost::posix_time::ptime m_last_recv_stake_txs; + boost::posix_time::ptime m_last_recv_stakes; boost::posix_time::ptime m_last_recv_blockchain_based_list; }; diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 90e2b145..8aa738c4 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -23,9 +23,9 @@ namespace graft::supernode::request { struct SupernodeAnnounce; } namespace graft { /*! - * \brief Stake transaction description + * \brief Supernode stake description */ -struct stake_transaction +struct supernode_stake { uint64_t amount = 0; uint64_t block_height = 0; @@ -106,14 +106,14 @@ class Supernode bool testnet); /*! - * \brief createFromStakeTransaction - creates new Supernode instance from stake transaction - * \param transaction - stake transaction - * \param testnet - testnet flag - * \return - Supernode pointer on success + * \brief createFromStake - creates new Supernode instance from a stake + * \param stake - stake of the supernode + * \param testnet - testnet flag + * \return - Supernode pointer on success */ - static Supernode * createFromStakeTransaction(const stake_transaction& transaction, - const std::string &daemon_address, - bool testnet); + static Supernode * createFromStake(const supernode_stake& stake, + const std::string &daemon_address, + bool testnet); bool prepareAnnounce(graft::supernode::request::SupernodeAnnounce& announce); @@ -196,28 +196,28 @@ class Supernode bool busy() const; /*! - * \brief stakeTransactionBlockHeight - height of block for stake transaction - * \return - height of block + * \brief stakeBlockHeight - height of block for stake + * \return - height of block */ - uint64_t stakeTransactionBlockHeight() const; + uint64_t stakeBlockHeight() const; /*! - * \brief setStakeTransactionBlock - set height of block for stake transaction - * \param - height of block + * \brief setStakeBlock - set height of block for stake + * \param - height of block */ - void setStakeTransactionBlockHeight(uint64_t blockHeight); + void setStakeBlockHeight(uint64_t blockHeight); /*! - * \brief stakeTransactionUnlockTime - number of blocks for unlocking stake transaction + * \brief stakeUnlockTime - number of blocks for unlocking stake * \return */ - uint64_t stakeTransactionUnlockTime() const; + uint64_t stakeUnlockTime() const; /*! - * \brief setStakeTransactionUnlockTime - set number of blocks for unlocking stake transaction - * \param - height of block + * \brief setStakeUnlockTime - set number of blocks for unlocking stake + * \param - height of block */ - void setStakeTransactionUnlockTime(uint64_t unlockTime); + void setStakeUnlockTime(uint64_t unlockTime); /*! * \brief loadKeys @@ -253,8 +253,8 @@ class Supernode bool m_has_secret_key = false; std::atomic m_last_update_time; std::atomic m_stake_amount; - std::atomic m_stake_transaction_block_height; - std::atomic m_stake_transaction_unlock_time; + std::atomic m_stake_block_height; + std::atomic m_stake_unlock_time; bool m_testnet = false; std::string m_network_address; }; diff --git a/include/supernode/requests/send_supernode_stake_txs.h b/include/supernode/requests/send_supernode_stake_txs.h deleted file mode 100644 index 9f6fedb6..00000000 --- a/include/supernode/requests/send_supernode_stake_txs.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "lib/graft/router.h" -#include "lib/graft/inout.h" -#include "lib/graft/jsonrpc.h" - -namespace graft::supernode::request { - -GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransaction, - (std::string, hash, std::string()), - (uint64_t, amount, 0), - (uint32_t, tier, 0), - (uint64_t, block_height, 0), - (uint64_t, unlock_time, 0), - (std::string, supernode_public_id, std::string()), - (std::string, supernode_public_address, std::string()) - ); - -GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakeTransactions, - (std::vector, stake_txs, std::vector()) - ); - -GRAFT_DEFINE_IO_STRUCT_INITED(SendSupernodeStakeTransactionsResponse, - (int, status, 0) - ); - -GRAFT_DEFINE_JSON_RPC_REQUEST(SendSupernodeStakeTransactionsJsonRpcRequest, SupernodeStakeTransactions); -GRAFT_DEFINE_JSON_RPC_RESPONSE_RESULT(SendSupernodeStakeTransactionsJsonRpcResponse, SendSupernodeStakeTransactionsResponse); - -void registerSendSupernodeStakeTransactionsRequest(graft::Router &router); - -} diff --git a/include/supernode/requests/send_supernode_stakes.h b/include/supernode/requests/send_supernode_stakes.h new file mode 100644 index 00000000..bf0d996c --- /dev/null +++ b/include/supernode/requests/send_supernode_stakes.h @@ -0,0 +1,31 @@ +#pragma once + +#include "lib/graft/router.h" +#include "lib/graft/inout.h" +#include "lib/graft/jsonrpc.h" + +namespace graft::supernode::request { + +GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStake, + (uint64_t, amount, 0), + (uint32_t, tier, 0), + (uint64_t, block_height, 0), + (uint64_t, unlock_time, 0), + (std::string, supernode_public_id, std::string()), + (std::string, supernode_public_address, std::string()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakes, + (std::vector, stakes, std::vector()) + ); + +GRAFT_DEFINE_IO_STRUCT_INITED(SendSupernodeStakesResponse, + (int, status, 0) + ); + +GRAFT_DEFINE_JSON_RPC_REQUEST(SendSupernodeStakesJsonRpcRequest, SupernodeStakes); +GRAFT_DEFINE_JSON_RPC_RESPONSE_RESULT(SendSupernodeStakesJsonRpcResponse, SendSupernodeStakesResponse); + +void registerSendSupernodeStakesRequest(graft::Router &router); + +} diff --git a/modules/cryptonode b/modules/cryptonode index af5fe0e3..ad0241f2 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit af5fe0e36e4e7ec7bf1c6b5f1f8976fee82c7e07 +Subproject commit ad0241f25829c4c6c67bfeb751fdd2ad0ddcd9d1 diff --git a/src/rta/DaemonRpcClient.cpp b/src/rta/DaemonRpcClient.cpp index a7b018df..d6e2d7cc 100644 --- a/src/rta/DaemonRpcClient.cpp +++ b/src/rta/DaemonRpcClient.cpp @@ -172,18 +172,18 @@ bool DaemonRpcClient::get_block_hash(uint64_t height, string &hash) return true; } -bool DaemonRpcClient::send_supernode_stake_txs(const char* network_address, const char* id) +bool DaemonRpcClient::send_supernode_stakes(const char* network_address, const char* id) { - epee::json_rpc::request req = AUTO_VAL_INIT(req); - epee::json_rpc::response res = AUTO_VAL_INIT(res); + epee::json_rpc::request req = AUTO_VAL_INIT(req); + epee::json_rpc::response res = AUTO_VAL_INIT(res); req.jsonrpc = "2.0"; req.id = epee::serialization::storage_entry(0); - req.method = "send_supernode_stake_txs"; + req.method = "send_supernode_stakes"; req.params.network_address = network_address; req.params.supernode_public_id = id; bool r = epee::net_utils::invoke_http_json("/json_rpc/rta", req, res, m_http_client, m_rpc_timeout); if (!r) { - LOG_ERROR("/json_rpc/rta/send_supernode_stake_txs error"); + LOG_ERROR("/json_rpc/rta/send_supernode_stakes error"); return false; } diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 6b245fda..1bc3f2a6 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -15,7 +15,7 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "supernode.fullsupernodelist" -constexpr size_t STAKE_TRANSACTIONS_RECV_TIMEOUT_SECONDS = 600; +constexpr size_t STAKES_RECV_TIMEOUT_SECONDS = 600; constexpr size_t BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS = 180; constexpr size_t BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT = 10; @@ -133,7 +133,7 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_rpc_client(daemon_address, "", "") , m_tp(new utils::ThreadPool()) , m_blockchain_based_list_max_block_number() - , m_last_recv_stake_txs(boost::date_time::not_a_date_time) + , m_last_recv_stakes(boost::date_time::not_a_date_time) , m_last_recv_blockchain_based_list(boost::date_time::not_a_date_time) { m_refresh_counter = 0; @@ -431,9 +431,9 @@ size_t FullSupernodeList::refreshedItems() const return m_refresh_counter; } -void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& stake_txs, const std::string& cryptonode_rpc_address, bool testnet) +void FullSupernodeList::updateStakes(const supernode_stake_array& stakes, const std::string& cryptonode_rpc_address, bool testnet) { - MDEBUG("update stake transactions"); + MDEBUG("update stakes"); boost::unique_lock writerLock(m_access); @@ -447,76 +447,43 @@ void FullSupernodeList::updateStakeTransactions(const stake_transaction_array& s continue; sn->setStakeAmount(0); - sn->setStakeTransactionBlockHeight(0); - sn->setStakeTransactionUnlockTime(0); + sn->setStakeBlockHeight(0); + sn->setStakeUnlockTime(0); } //update supernodes - for (const stake_transaction& tx : stake_txs) + for (const supernode_stake& stake : stakes) { - auto it = m_list.find(tx.supernode_public_id); + auto it = m_list.find(stake.supernode_public_id); - if (it != m_list.end()) + if (it == m_list.end()) { - SupernodePtr sn = it->second; - - //aggregate stake transaction fields for supernode - - if (tx.amount) - { - if (sn->stakeAmount()) - { - sn->setStakeAmount(sn->stakeAmount() + tx.amount); - - //find intersection of stake transaction intervals - - uint64_t min_block_height = sn->stakeTransactionBlockHeight(), - max_block_height = min_block_height + sn->stakeTransactionUnlockTime(), - min_tx_block_height = tx.block_height, - max_tx_block_height = min_tx_block_height + tx.unlock_time; - - if (min_tx_block_height > min_block_height) - min_block_height = min_tx_block_height; - - if (max_tx_block_height < max_block_height) - max_block_height = max_tx_block_height; - - if (max_block_height <= min_block_height) - { - sn->setStakeAmount(0); - - max_block_height = min_block_height; - } - - sn->setStakeTransactionBlockHeight(min_block_height); - sn->setStakeTransactionUnlockTime(max_block_height - min_block_height); - } - else - { - sn->setStakeAmount(tx.amount); - sn->setStakeTransactionBlockHeight(tx.block_height); - sn->setStakeTransactionUnlockTime(tx.unlock_time); - } - } - } - else - { - SupernodePtr sn (Supernode::createFromStakeTransaction(tx, cryptonode_rpc_address, testnet)); + SupernodePtr sn (Supernode::createFromStake(stake, cryptonode_rpc_address, testnet)); if (!sn) { - LOG_ERROR("Cant create watch-only supernode wallet for id: " << tx.supernode_public_id); + LOG_ERROR("Cant create watch-only supernode wallet for id: " << stake.supernode_public_id); continue; } MINFO("About to add supernode to list [" << sn << "]: " << sn->idKeyAsString()); addImpl(sn); + + continue; } + + //update stake + + SupernodePtr sn = it->second; + + sn->setStakeAmount(stake.amount); + sn->setStakeBlockHeight(stake.block_height); + sn->setStakeUnlockTime(stake.unlock_time); } - m_last_recv_stake_txs = boost::posix_time::second_clock::local_time(); + m_last_recv_stakes = boost::posix_time::second_clock::local_time(); } namespace @@ -536,9 +503,9 @@ bool is_timeout_expired(const boost::posix_time::ptime& last_recv_time, size_t t void FullSupernodeList::synchronizeWithCryptonode(const char* network_address, const char* address) { - if (is_timeout_expired(m_last_recv_stake_txs, STAKE_TRANSACTIONS_RECV_TIMEOUT_SECONDS)) + if (is_timeout_expired(m_last_recv_stakes, STAKES_RECV_TIMEOUT_SECONDS)) { - m_rpc_client.send_supernode_stake_txs(network_address, address); + m_rpc_client.send_supernode_stakes(network_address, address); } if (is_timeout_expired(m_last_recv_blockchain_based_list, BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS)) diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 4633bfa3..6c0c067c 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -30,8 +30,8 @@ Supernode::Supernode(const string &wallet_address, const crypto::public_key &id_ , m_has_secret_key(false) , m_last_update_time {0} , m_stake_amount() - , m_stake_transaction_block_height() - , m_stake_transaction_unlock_time() + , m_stake_block_height() + , m_stake_unlock_time() , m_testnet(testnet) { MINFO("supernode created: " << "[" << this << "] " << this->walletAddress() << ", " << this->idKeyAsString()); @@ -102,7 +102,7 @@ Supernode *Supernode::createFromAnnounce(const SupernodeAnnounce &announce, cons bool Supernode::prepareAnnounce(SupernodeAnnounce &announce) { announce.supernode_public_id = this->idKeyAsString(); - announce.height = m_stake_transaction_block_height; + announce.height = m_stake_block_height; crypto::signature sign; if (!signMessage(announce.supernode_public_id + to_string(announce.height), sign)) @@ -113,20 +113,20 @@ bool Supernode::prepareAnnounce(SupernodeAnnounce &announce) return true; } -Supernode* Supernode::createFromStakeTransaction(const stake_transaction& transaction, const std::string &daemon_address, bool testnet) +Supernode* Supernode::createFromStake(const supernode_stake& stake, const std::string &daemon_address, bool testnet) { crypto::public_key id_key; - if (!epee::string_tools::hex_to_pod(transaction.supernode_public_id, id_key)) { - MERROR("Failed to parse id key from stake transaction: " << transaction.supernode_public_id); + if (!epee::string_tools::hex_to_pod(stake.supernode_public_id, id_key)) { + MERROR("Failed to parse id key from stake: " << stake.supernode_public_id); return nullptr; } - std::unique_ptr result (new Supernode(transaction.supernode_public_address, id_key, daemon_address, testnet)); + std::unique_ptr result (new Supernode(stake.supernode_public_address, id_key, daemon_address, testnet)); result->setLastUpdateTime(time(nullptr)); - result->setStakeAmount(transaction.amount); - result->setStakeTransactionBlockHeight(transaction.block_height); - result->setStakeTransactionUnlockTime(transaction.unlock_time); + result->setStakeAmount(stake.amount); + result->setStakeBlockHeight(stake.block_height); + result->setStakeUnlockTime(stake.unlock_time); return result.release(); } @@ -225,24 +225,24 @@ bool Supernode::busy() const return false; } -uint64_t Supernode::stakeTransactionBlockHeight() const +uint64_t Supernode::stakeBlockHeight() const { - return m_stake_transaction_block_height; + return m_stake_block_height; } -void Supernode::setStakeTransactionBlockHeight(uint64_t blockHeight) +void Supernode::setStakeBlockHeight(uint64_t blockHeight) { - m_stake_transaction_block_height.store(blockHeight); + m_stake_block_height.store(blockHeight); } -uint64_t Supernode::stakeTransactionUnlockTime() const +uint64_t Supernode::stakeUnlockTime() const { - return m_stake_transaction_unlock_time; + return m_stake_unlock_time; } -void Supernode::setStakeTransactionUnlockTime(uint64_t unlockTime) +void Supernode::setStakeUnlockTime(uint64_t unlockTime) { - m_stake_transaction_unlock_time.store(unlockTime); + m_stake_unlock_time.store(unlockTime); } bool Supernode::loadKeys(const string &filename) diff --git a/src/supernode/requests.cpp b/src/supernode/requests.cpp index 0fdcf5f8..412707ab 100644 --- a/src/supernode/requests.cpp +++ b/src/supernode/requests.cpp @@ -15,7 +15,7 @@ #include "supernode/requests/send_raw_tx.h" #include "supernode/requests/authorize_rta_tx.h" #include "supernode/requests/send_supernode_announce.h" -#include "supernode/requests/send_supernode_stake_txs.h" +#include "supernode/requests/send_supernode_stakes.h" #include "supernode/requests/blockchain_based_list.h" namespace graft::supernode::request::debug { void __registerDebugRequests(Router& router); } @@ -35,7 +35,7 @@ void registerRTARequests(graft::Router &router) registerRejectPayRequest(router); registerAuthorizeRtaTxRequests(router); registerSendSupernodeAnnounceRequest(router); - registerSendSupernodeStakeTransactionsRequest(router); + registerSendSupernodeStakesRequest(router); registerBlockchainBasedListRequest(router); } diff --git a/src/supernode/requests/send_supernode_stake_txs.cpp b/src/supernode/requests/send_supernode_stakes.cpp similarity index 71% rename from src/supernode/requests/send_supernode_stake_txs.cpp rename to src/supernode/requests/send_supernode_stakes.cpp index 625bd150..8c228110 100644 --- a/src/supernode/requests/send_supernode_stake_txs.cpp +++ b/src/supernode/requests/send_supernode_stakes.cpp @@ -26,7 +26,7 @@ // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "supernode/requests/send_supernode_stake_txs.h" +#include "supernode/requests/send_supernode_stakes.h" #include "supernode/requestdefines.h" #include "rta/fullsupernodelist.h" #include "rta/supernode.h" @@ -35,10 +35,10 @@ #include #undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "supernode.sendsupernodestaketxsrequest" +#define MONERO_DEFAULT_LOG_CATEGORY "supernode.sendsupernodestakesrequest" namespace { - static const char* PATH = "/send_supernode_stake_txs"; + static const char* PATH = "/send_supernode_stakes"; } namespace graft::supernode::request { @@ -46,7 +46,7 @@ namespace graft::supernode::request { namespace { -Status supernodeStakeTransactionsHandler +Status supernodeStakesHandler (const Router::vars_t& vars, const graft::Input& input, graft::Context& ctx, @@ -67,7 +67,7 @@ Status supernodeStakeTransactionsHandler return Status::Error; } - SendSupernodeStakeTransactionsJsonRpcRequest req; + SendSupernodeStakesJsonRpcRequest req; if (!input.get(req)) { @@ -76,38 +76,39 @@ Status supernodeStakeTransactionsHandler return Status::Error; } - // handle stake Transactions - const std::vector& src_stake_txs = req.params.stake_txs; - FullSupernodeList::stake_transaction_array dst_stake_txs; + // handle stakes - dst_stake_txs.reserve(src_stake_txs.size()); + const std::vector& src_stakes = req.params.stakes; + FullSupernodeList::supernode_stake_array dst_stakes; - for (const SupernodeStakeTransaction& src_tx : src_stake_txs) + dst_stakes.reserve(src_stakes.size()); + + for (const SupernodeStake& src_stake : src_stakes) { - stake_transaction dst_tx; + supernode_stake dst_stake; - dst_tx.amount = src_tx.amount; - dst_tx.block_height = src_tx.block_height; - dst_tx.unlock_time = src_tx.unlock_time; - dst_tx.supernode_public_id = src_tx.supernode_public_id; - dst_tx.supernode_public_address = src_tx.supernode_public_address; + dst_stake.amount = src_stake.amount; + dst_stake.block_height = src_stake.block_height; + dst_stake.unlock_time = src_stake.unlock_time; + dst_stake.supernode_public_id = src_stake.supernode_public_id; + dst_stake.supernode_public_address = src_stake.supernode_public_address; - dst_stake_txs.emplace_back(std::move(dst_tx)); + dst_stakes.emplace_back(std::move(dst_stake)); } std::string cryptonode_rpc_address = ctx.global["cryptonode_rpc_address"]; bool testnet = ctx.global["testnet"]; - fsl->updateStakeTransactions(dst_stake_txs, cryptonode_rpc_address, testnet); + fsl->updateStakes(dst_stakes, cryptonode_rpc_address, testnet); return Status::Ok; } } -void registerSendSupernodeStakeTransactionsRequest(graft::Router &router) +void registerSendSupernodeStakesRequest(graft::Router &router) { - Router::Handler3 h3(nullptr, supernodeStakeTransactionsHandler, nullptr); + Router::Handler3 h3(nullptr, supernodeStakesHandler, nullptr); router.addRoute(PATH, METHOD_POST, h3); From 43ac541808f2f6db63cc86a27c9a2d960a8a706e Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Sun, 10 Mar 2019 02:58:36 +0100 Subject: [PATCH 65/85] Linking blockchain based list and supernode stakes based on block number --- include/rta/fullsupernodelist.h | 1 + include/supernode/requests/blockchain_based_list.h | 3 ++- modules/cryptonode | 2 +- src/supernode/requests/blockchain_based_list.cpp | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index cc395166..e662c572 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -138,6 +138,7 @@ class FullSupernodeList { std::string supernode_public_id; std::string supernode_public_address; + uint64_t amount; }; typedef std::vector blockchain_based_list_tier; diff --git a/include/supernode/requests/blockchain_based_list.h b/include/supernode/requests/blockchain_based_list.h index 377be3ea..8c0a1d24 100644 --- a/include/supernode/requests/blockchain_based_list.h +++ b/include/supernode/requests/blockchain_based_list.h @@ -8,7 +8,8 @@ namespace graft::supernode::request { GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTierEntry, (std::string, supernode_public_id, std::string()), - (std::string, supernode_public_address, std::string()) + (std::string, supernode_public_address, std::string()), + (uint64_t, amount, 0) ); GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTier, diff --git a/modules/cryptonode b/modules/cryptonode index ad0241f2..4d4be6b3 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit ad0241f25829c4c6c67bfeb751fdd2ad0ddcd9d1 +Subproject commit 4d4be6b36d828abe0e238bea6ac4f1bdbf2385b1 diff --git a/src/supernode/requests/blockchain_based_list.cpp b/src/supernode/requests/blockchain_based_list.cpp index c52e7aca..07b2295a 100644 --- a/src/supernode/requests/blockchain_based_list.cpp +++ b/src/supernode/requests/blockchain_based_list.cpp @@ -94,6 +94,7 @@ Status blockchainBasedListHandler entry.supernode_public_id = supernode_desc.supernode_public_id; entry.supernode_public_address = supernode_desc.supernode_public_address; + entry.amount = supernode_desc.amount; supernodes.emplace_back(std::move(entry)); } From 41c40f353cea9ec74aa72f56ce24daec62c499b2 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 11 Mar 2019 15:13:35 +0100 Subject: [PATCH 66/85] Set wallet address during stakes update --- include/rta/supernode.h | 31 +++++++++++++------------------ src/rta/fullsupernodelist.cpp | 9 +++------ src/rta/supernode.cpp | 32 +++++++++++++++++--------------- 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/include/rta/supernode.h b/include/rta/supernode.h index 8aa738c4..396949bb 100644 --- a/include/rta/supernode.h +++ b/include/rta/supernode.h @@ -70,12 +70,6 @@ class Supernode */ uint64_t stakeAmount() const; - /*! - * \brief setStakeAmount - set stake amount - * \param - amount - */ - void setStakeAmount(uint64_t amount); - /*! * \brief tier - returns the tier of this supernode based on its stake amount * \return - the tier (1-4) of the supernode or 0 if the verified stake amount is below tier 1 @@ -87,6 +81,10 @@ class Supernode */ std::string walletAddress() const; + /*! + * \brief setWalletAddress - sets wallet public address + */ + void setWalletAddress(const std::string &address); /*! * \brief updateFromAnnounce - updates supernode from announce (helper to extract signed key images from graft::supernode::request::SupernodeAnnounce) @@ -201,12 +199,6 @@ class Supernode */ uint64_t stakeBlockHeight() const; - /*! - * \brief setStakeBlock - set height of block for stake - * \param - height of block - */ - void setStakeBlockHeight(uint64_t blockHeight); - /*! * \brief stakeUnlockTime - number of blocks for unlocking stake * \return @@ -214,10 +206,12 @@ class Supernode uint64_t stakeUnlockTime() const; /*! - * \brief setStakeUnlockTime - set number of blocks for unlocking stake - * \param - height of block + * \brief setStake - set stake details + * \param - stake amount + * \param - height of block + * \param - unlock time */ - void setStakeUnlockTime(uint64_t unlockTime); + void setStake(uint64_t amount, uint64_t blockHeight, uint64_t unlockTime); /*! * \brief loadKeys @@ -247,14 +241,15 @@ class Supernode private: // wallet's address. empty in case 'their' supernode + mutable boost::shared_mutex m_access; std::string m_wallet_address; crypto::public_key m_id_key; crypto::secret_key m_secret_key; bool m_has_secret_key = false; std::atomic m_last_update_time; - std::atomic m_stake_amount; - std::atomic m_stake_block_height; - std::atomic m_stake_unlock_time; + uint64_t m_stake_amount; + uint64_t m_stake_block_height; + uint64_t m_stake_unlock_time; bool m_testnet = false; std::string m_network_address; }; diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 1bc3f2a6..77e2a2da 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -446,9 +446,7 @@ void FullSupernodeList::updateStakes(const supernode_stake_array& stakes, const if (!sn) continue; - sn->setStakeAmount(0); - sn->setStakeBlockHeight(0); - sn->setStakeUnlockTime(0); + sn->setStake(0, 0, 0); } //update supernodes @@ -478,9 +476,8 @@ void FullSupernodeList::updateStakes(const supernode_stake_array& stakes, const SupernodePtr sn = it->second; - sn->setStakeAmount(stake.amount); - sn->setStakeBlockHeight(stake.block_height); - sn->setStakeUnlockTime(stake.unlock_time); + sn->setStake(stake.amount, stake.block_height, stake.unlock_time); + sn->setWalletAddress(stake.supernode_public_address); } m_last_recv_stakes = boost::posix_time::second_clock::local_time(); diff --git a/src/rta/supernode.cpp b/src/rta/supernode.cpp index 6c0c067c..d9ccdaa2 100644 --- a/src/rta/supernode.cpp +++ b/src/rta/supernode.cpp @@ -45,14 +45,10 @@ Supernode::~Supernode() uint64_t Supernode::stakeAmount() const { + boost::shared_lock readerLock(m_access); return m_stake_amount; } -void Supernode::setStakeAmount(uint64_t amount) -{ - m_stake_amount = amount; -} - uint32_t Supernode::tier() const { auto stake = stakeAmount(); @@ -65,9 +61,16 @@ uint32_t Supernode::tier() const string Supernode::walletAddress() const { + boost::shared_lock readerLock(m_access); return m_wallet_address; } +void Supernode::setWalletAddress(const std::string &address) +{ + boost::unique_lock writerLock(m_access); + + m_wallet_address = address; +} bool Supernode::updateFromAnnounce(const SupernodeAnnounce &announce) { @@ -124,9 +127,7 @@ Supernode* Supernode::createFromStake(const supernode_stake& stake, const std::s std::unique_ptr result (new Supernode(stake.supernode_public_address, id_key, daemon_address, testnet)); result->setLastUpdateTime(time(nullptr)); - result->setStakeAmount(stake.amount); - result->setStakeBlockHeight(stake.block_height); - result->setStakeUnlockTime(stake.unlock_time); + result->setStake(stake.amount, stake.block_height, stake.unlock_time); return result.release(); } @@ -227,24 +228,25 @@ bool Supernode::busy() const uint64_t Supernode::stakeBlockHeight() const { + boost::shared_lock readerLock(m_access); return m_stake_block_height; } -void Supernode::setStakeBlockHeight(uint64_t blockHeight) +void Supernode::setStake(uint64_t stakeAmount, uint64_t blockHeight, uint64_t unlockTime) { - m_stake_block_height.store(blockHeight); + boost::unique_lock writerLock(m_access); + + m_stake_amount = stakeAmount; + m_stake_block_height = blockHeight; + m_stake_unlock_time = unlockTime; } uint64_t Supernode::stakeUnlockTime() const { + boost::shared_lock readerLock(m_access); return m_stake_unlock_time; } -void Supernode::setStakeUnlockTime(uint64_t unlockTime) -{ - m_stake_unlock_time.store(unlockTime); -} - bool Supernode::loadKeys(const string &filename) { if (!boost::filesystem::exists(filename)) { From 18b1bc48ecb68c764c775e54fea40fdd5003c1cf Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 11 Mar 2019 16:28:18 +0100 Subject: [PATCH 67/85] Add auth sample block number to buildAuthSample --- include/rta/fullsupernodelist.h | 15 ++++++++------- src/rta/fullsupernodelist.cpp | 8 +++++--- src/supernode/requests/debug.cpp | 7 ++++--- src/supernode/requests/pay.cpp | 6 ++++-- src/supernode/requests/sale.cpp | 3 ++- src/supernode/requests/sale_details.cpp | 6 ++++-- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index e662c572..0e8cc8c4 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -87,15 +87,16 @@ class FullSupernodeList typedef std::vector supernode_array; /*! - * \brief buildAuthSample - builds auth sample (8 supernodes) for given block height - * \param height - block height used to perform selection - * \param payment_id - payment id which is used for building auth sample - * \param out - vector of supernode pointers - * \return - true on success + * \brief buildAuthSample - builds auth sample (8 supernodes) for given block height + * \param height - block height used to perform selection + * \param payment_id - payment id which is used for building auth sample + * \param out - vector of supernode pointers + * \param out_auth_block_number - block number which was used for auth sample + * \return - true on success */ - bool buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out); + bool buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out, uint64_t &out_auth_block_number); - bool buildAuthSample(const std::string& payment_id, supernode_array &out); + bool buildAuthSample(const std::string& payment_id, supernode_array &out, uint64_t &out_auth_block_number); /*! * \brief items - returns address list of known supernodes diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index 77e2a2da..c733f5cb 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -276,10 +276,12 @@ bool FullSupernodeList::selectSupernodes(size_t items_count, const std::string& return true; } -bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out) +bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out, uint64_t &out_auth_block_number) { uint64_t blockchain_based_list_height = height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT; + out_auth_block_number = blockchain_based_list_height; + MDEBUG("building auth sample for height " << height << "(blockchain_based_list_height=" << blockchain_based_list_height << ") and PaymentID '" << payment_id << "'"); std::array tier_supernodes; @@ -385,9 +387,9 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym return out.size() == AUTH_SAMPLE_SIZE; } -bool FullSupernodeList::buildAuthSample(const string &payment_id, FullSupernodeList::supernode_array &out) +bool FullSupernodeList::buildAuthSample(const string &payment_id, FullSupernodeList::supernode_array &out, uint64_t &out_auth_block_number) { - return buildAuthSample(getBlockchainBasedListMaxBlockNumber(), payment_id, out); + return buildAuthSample(getBlockchainBasedListMaxBlockNumber(), payment_id, out, out_auth_block_number); } vector FullSupernodeList::items() const diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 37dc7602..438cc232 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -85,7 +85,7 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); std::vector sample; - + uint64_t sample_block_number = 0; std::string payment_id; try @@ -98,14 +98,15 @@ Status getAuthSample(const Router::vars_t& vars, const graft::Input& input, } SupernodeListJsonRpcResult resp; - resp.result.height = fsl->getBlockchainBasedListMaxBlockNumber(); - const bool ok = fsl->buildAuthSample(resp.result.height, payment_id, sample); + const bool ok = fsl->buildAuthSample(fsl->getBlockchainBasedListMaxBlockNumber(), payment_id, sample, sample_block_number); if(!ok) { return errorInternalError("failed to build auth sample", output); } + resp.result.height = sample_block_number; + for(auto& sPtr : sample) { DbSupernode sn; diff --git a/src/supernode/requests/pay.cpp b/src/supernode/requests/pay.cpp index 5b2d4ca5..d1595379 100644 --- a/src/supernode/requests/pay.cpp +++ b/src/supernode/requests/pay.cpp @@ -119,7 +119,8 @@ Status handleClientPayRequest(const Router::vars_t& vars, const graft::Input& in } std::vector authSample; - if (!fsl->buildAuthSample(in.BlockNumber, in.PaymentID, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { + uint64_t auth_sample_block_number = 0; + if (!fsl->buildAuthSample(in.BlockNumber, in.PaymentID, authSample, auth_sample_block_number) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { return errorBuildAuthSample(output); } @@ -209,7 +210,8 @@ Status handleWaitingTxReply(const Router::vars_t& vars, const graft::Input& inpu } std::vector authSample; - if (!fsl->buildAuthSample(payData.BlockNumber, payData.PaymentID, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { + uint64_t auth_sample_block_number = 0; + if (!fsl->buildAuthSample(payData.BlockNumber, payData.PaymentID, authSample, auth_sample_block_number) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { return errorBuildAuthSample(output); } diff --git a/src/supernode/requests/sale.cpp b/src/supernode/requests/sale.cpp index 2bde8a64..2a4dd871 100644 --- a/src/supernode/requests/sale.cpp +++ b/src/supernode/requests/sale.cpp @@ -83,7 +83,8 @@ Status handleClientSaleRequest(const Router::vars_t& vars, const graft::Input& i // generate auth sample std::vector authSample; - if (!fsl->buildAuthSample(data.BlockNumber, payment_id, authSample) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { + uint64_t auth_sample_block_number = 0; + if (!fsl->buildAuthSample(data.BlockNumber, payment_id, authSample, auth_sample_block_number) || authSample.size() != FullSupernodeList::AUTH_SAMPLE_SIZE) { return errorCustomError(MESSAGE_RTA_CANT_BUILD_AUTH_SAMPLE, ERROR_INVALID_PARAMS, output); } diff --git a/src/supernode/requests/sale_details.cpp b/src/supernode/requests/sale_details.cpp index dafb82e3..c4bd1aaa 100644 --- a/src/supernode/requests/sale_details.cpp +++ b/src/supernode/requests/sale_details.cpp @@ -98,10 +98,11 @@ Status handleClientRequest(const Router::vars_t& vars, const graft::Input& input } vector authSample; + uint64_t auth_sample_block_number = 0; FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); SupernodePtr supernode = ctx.global.get(CONTEXT_KEY_SUPERNODE, SupernodePtr()); - if (!fsl->buildAuthSample(in.BlockNumber, in.PaymentID, authSample)) { + if (!fsl->buildAuthSample(in.BlockNumber, in.PaymentID, authSample, auth_sample_block_number)) { return errorBuildAuthSample(output); } // we have sale details locally, easy way @@ -285,13 +286,14 @@ Status handleSaleDetailsUnicastRequest(const Router::vars_t& vars, const graft:: } vector authSample; + uint64_t auth_sample_block_number = 0; FullSupernodeListPtr fsl = ctx.global.get(CONTEXT_KEY_FULLSUPERNODELIST, FullSupernodeListPtr()); MDEBUG("sale_details request from remote supernode: " << unicastReq.sender_address << ", payment: " << sdr.PaymentID << ", block: " << sdr.BlockNumber); - if (!fsl->buildAuthSample(sdr.BlockNumber, sdr.PaymentID, authSample)) { + if (!fsl->buildAuthSample(sdr.BlockNumber, sdr.PaymentID, authSample, auth_sample_block_number)) { LOG_ERROR("failed to build auth sample for block: " << sdr.BlockNumber << ", payment: " << sdr.PaymentID); return sendOkResponseToCryptonode(output); // cryptonode doesn't care about any errors, it's job is only deliver request From 7682337a53889b0934613aab52eaf79752d63604 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 11 Mar 2019 18:25:41 +0100 Subject: [PATCH 68/85] block_number->block_height in RPC requests. Supernode to cryptonode requests timeouts optimization. Adding block_height to stakes request from cryptonode to supernode --- include/rta/fullsupernodelist.h | 7 ++-- .../requests/blockchain_based_list.h | 2 +- .../requests/send_supernode_stakes.h | 1 + modules/cryptonode | 2 +- src/rta/fullsupernodelist.cpp | 35 ++++++++++++------- .../requests/blockchain_based_list.cpp | 2 +- .../requests/send_supernode_stakes.cpp | 2 +- 7 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 0e8cc8c4..b835ac85 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -133,7 +133,7 @@ class FullSupernodeList * \param - array of stakes * \return */ - void updateStakes(const supernode_stake_array& stakes, const std::string& cryptonode_rpc_address, bool testnet); + void updateStakes(uint64_t block_number, const supernode_stake_array& stakes, const std::string& cryptonode_rpc_address, bool testnet); struct blockchain_based_list_entry { @@ -189,10 +189,11 @@ class FullSupernodeList std::unique_ptr m_tp; std::atomic_size_t m_refresh_counter; uint64_t m_blockchain_based_list_max_block_number; + uint64_t m_stakes_max_block_number; blockchain_based_list_map m_blockchain_based_lists; std::mt19937_64 m_rng; - boost::posix_time::ptime m_last_recv_stakes; - boost::posix_time::ptime m_last_recv_blockchain_based_list; + boost::posix_time::ptime m_next_recv_stakes; + boost::posix_time::ptime m_next_recv_blockchain_based_list; }; using FullSupernodeListPtr = boost::shared_ptr; diff --git a/include/supernode/requests/blockchain_based_list.h b/include/supernode/requests/blockchain_based_list.h index 8c0a1d24..73f79170 100644 --- a/include/supernode/requests/blockchain_based_list.h +++ b/include/supernode/requests/blockchain_based_list.h @@ -17,7 +17,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTier, ); GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedList, - (uint64_t, block_number, uint64_t()), + (uint64_t, block_height, uint64_t()), (std::vector, tiers, std::vector()) ); diff --git a/include/supernode/requests/send_supernode_stakes.h b/include/supernode/requests/send_supernode_stakes.h index bf0d996c..b098deab 100644 --- a/include/supernode/requests/send_supernode_stakes.h +++ b/include/supernode/requests/send_supernode_stakes.h @@ -16,6 +16,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStake, ); GRAFT_DEFINE_IO_STRUCT_INITED(SupernodeStakes, + (uint64_t, block_height, 0), (std::vector, stakes, std::vector()) ); diff --git a/modules/cryptonode b/modules/cryptonode index 4d4be6b3..7bdb2fbc 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 4d4be6b36d828abe0e238bea6ac4f1bdbf2385b1 +Subproject commit 7bdb2fbc00fa2a1fb2ed5492c182f2148b32f59f diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index c733f5cb..e7df51fa 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -18,6 +18,7 @@ constexpr size_t STAKES_RECV_TIMEOUT_SECONDS = 600; constexpr size_t BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS = 180; constexpr size_t BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT = 10; +constexpr size_t REPEATED_REQUEST_DELAY_SECONDS = 10; namespace fs = boost::filesystem; using namespace boost::multiprecision; @@ -133,8 +134,9 @@ FullSupernodeList::FullSupernodeList(const string &daemon_address, bool testnet) , m_rpc_client(daemon_address, "", "") , m_tp(new utils::ThreadPool()) , m_blockchain_based_list_max_block_number() - , m_last_recv_stakes(boost::date_time::not_a_date_time) - , m_last_recv_blockchain_based_list(boost::date_time::not_a_date_time) + , m_stakes_max_block_number() + , m_next_recv_stakes(boost::date_time::not_a_date_time) + , m_next_recv_blockchain_based_list(boost::date_time::not_a_date_time) { m_refresh_counter = 0; } @@ -433,12 +435,18 @@ size_t FullSupernodeList::refreshedItems() const return m_refresh_counter; } -void FullSupernodeList::updateStakes(const supernode_stake_array& stakes, const std::string& cryptonode_rpc_address, bool testnet) +void FullSupernodeList::updateStakes(uint64_t block_number, const supernode_stake_array& stakes, const std::string& cryptonode_rpc_address, bool testnet) { MDEBUG("update stakes"); boost::unique_lock writerLock(m_access); + if (block_number <= m_stakes_max_block_number) + { + MDEBUG("stakes for block #" << block_number << " have already been received (last stakes have been received for block #" << m_stakes_max_block_number << ")"); + return; + } + //clear supernode data for (const std::unordered_map::value_type& sn_desc : m_list) @@ -482,32 +490,35 @@ void FullSupernodeList::updateStakes(const supernode_stake_array& stakes, const sn->setWalletAddress(stake.supernode_public_address); } - m_last_recv_stakes = boost::posix_time::second_clock::local_time(); + m_stakes_max_block_number = block_number; + m_next_recv_stakes = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(STAKES_RECV_TIMEOUT_SECONDS); } namespace { -bool is_timeout_expired(const boost::posix_time::ptime& last_recv_time, size_t timeout_seconds) +bool check_timeout_expired(boost::posix_time::ptime& next_recv_time) { - if (last_recv_time.is_not_a_date_time()) - return true; + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - boost::posix_time::time_duration duration = boost::posix_time::second_clock::local_time() - last_recv_time; + if (!next_recv_time.is_special() && next_recv_time > now) + return false; - return duration > boost::posix_time::seconds(timeout_seconds); + next_recv_time = now + boost::posix_time::seconds(REPEATED_REQUEST_DELAY_SECONDS); + + return true; } } void FullSupernodeList::synchronizeWithCryptonode(const char* network_address, const char* address) { - if (is_timeout_expired(m_last_recv_stakes, STAKES_RECV_TIMEOUT_SECONDS)) + if (check_timeout_expired(m_next_recv_stakes)) { m_rpc_client.send_supernode_stakes(network_address, address); } - if (is_timeout_expired(m_last_recv_blockchain_based_list, BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS)) + if (check_timeout_expired(m_next_recv_blockchain_based_list)) { m_rpc_client.send_supernode_blockchain_based_list(network_address, address, m_blockchain_based_list_max_block_number); } @@ -544,7 +555,7 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc return; } - m_last_recv_blockchain_based_list = boost::posix_time::second_clock::local_time(); + m_next_recv_blockchain_based_list = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(BLOCKCHAIN_BASED_LIST_RECV_TIMEOUT_SECONDS); m_blockchain_based_lists[block_number] = list; diff --git a/src/supernode/requests/blockchain_based_list.cpp b/src/supernode/requests/blockchain_based_list.cpp index 07b2295a..8cc82696 100644 --- a/src/supernode/requests/blockchain_based_list.cpp +++ b/src/supernode/requests/blockchain_based_list.cpp @@ -102,7 +102,7 @@ Status blockchainBasedListHandler tiers.emplace_back(std::move(supernodes)); } - fsl->setBlockchainBasedList(req.params.block_number, FullSupernodeList::blockchain_based_list_ptr( + fsl->setBlockchainBasedList(req.params.block_height, FullSupernodeList::blockchain_based_list_ptr( new FullSupernodeList::blockchain_based_list(std::move(tiers)))); return Status::Ok; diff --git a/src/supernode/requests/send_supernode_stakes.cpp b/src/supernode/requests/send_supernode_stakes.cpp index 8c228110..64d11f5a 100644 --- a/src/supernode/requests/send_supernode_stakes.cpp +++ b/src/supernode/requests/send_supernode_stakes.cpp @@ -99,7 +99,7 @@ Status supernodeStakesHandler std::string cryptonode_rpc_address = ctx.global["cryptonode_rpc_address"]; bool testnet = ctx.global["testnet"]; - fsl->updateStakes(dst_stakes, cryptonode_rpc_address, testnet); + fsl->updateStakes(req.params.block_height, dst_stakes, cryptonode_rpc_address, testnet); return Status::Ok; } From f9bff8dd90edc7c1927ef0f9fd5ea9088638aa5b Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 11 Mar 2019 20:47:42 +0300 Subject: [PATCH 69/85] Disabled "pay" request --- src/supernode/requests/pay.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/supernode/requests/pay.cpp b/src/supernode/requests/pay.cpp index d1595379..27d882de 100644 --- a/src/supernode/requests/pay.cpp +++ b/src/supernode/requests/pay.cpp @@ -99,6 +99,9 @@ Status handleClientPayRequest(const Router::vars_t& vars, const graft::Input& in graft::Context& ctx, graft::Output& output) { MDEBUG(__FUNCTION__ << " begin"); + // Disable pay request for RTA mining + return errorInternalError("Not implemented", output); + PayRequestJsonRpc req; if (!input.get(req)) { From fca03dfd434a58abd434df6318ae9f26567d57e8 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Mon, 11 Mar 2019 23:39:13 +0100 Subject: [PATCH 70/85] Update cryptonode module --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 7bdb2fbc..3d92859b 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 7bdb2fbc00fa2a1fb2ed5492c182f2148b32f59f +Subproject commit 3d92859b11778a9a6f0fb719f785593b89651099 From 0b891c8cabe55a49a370fd1ca914d0f21045b47a Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 12 Mar 2019 02:12:25 +0300 Subject: [PATCH 71/85] Updated cryptonode submodule --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 3d92859b..3ad63e24 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 3d92859b11778a9a6f0fb719f785593b89651099 +Subproject commit 3ad63e24889e4671f68db70cb34cc2f09fa45b52 From 15bb659c16163115799ea67df46f2e04ec87ec1e Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Sun, 10 Mar 2019 23:34:59 -0300 Subject: [PATCH 72/85] Increase minimum thread count to 2 A count < 2 throws an error in MPMCBoundedQueue for some undocumented, unexplained reason. --- include/lib/graft/thread_pool/thread_pool_options.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/lib/graft/thread_pool/thread_pool_options.hpp b/include/lib/graft/thread_pool/thread_pool_options.hpp index 057e9e96..4e454834 100644 --- a/include/lib/graft/thread_pool/thread_pool_options.hpp +++ b/include/lib/graft/thread_pool/thread_pool_options.hpp @@ -60,7 +60,7 @@ class ThreadPoolOptions /// Implementation inline ThreadPoolOptions::ThreadPoolOptions() - : m_thread_count(std::max(1u, std::thread::hardware_concurrency())) + : m_thread_count(std::max(2u, std::thread::hardware_concurrency())) , m_queue_size(1024u) , m_workers_expelling_interval_ms(1000u) { @@ -68,7 +68,7 @@ inline ThreadPoolOptions::ThreadPoolOptions() inline void ThreadPoolOptions::setThreadCount(size_t count) { - m_thread_count = std::max(1u, count); + m_thread_count = std::max(2u, count); } inline void ThreadPoolOptions::setQueueSize(size_t size) From 53b2bd97e1d6dac100da7a49098fb8f2c2f8f27e Mon Sep 17 00:00:00 2001 From: EDDragonWolf Date: Tue, 12 Mar 2019 07:06:18 -0700 Subject: [PATCH 73/85] Fixed version dependency for graft target --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56b3ac66..616b86d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,7 +225,7 @@ endif() set_target_properties(graft PROPERTIES LINK_FLAGS "-Wl,-E -rdynamic") -add_dependencies(graft libr3 cryptonode graftlet_lib) +add_dependencies(graft version libr3 cryptonode graftlet_lib) ### requests_common library add_library(requests_common STATIC From 54f5d2f0a2f0b47988d0b500daaa291c17e16f21 Mon Sep 17 00:00:00 2001 From: Leny Kholodov Date: Tue, 12 Mar 2019 17:15:27 +0100 Subject: [PATCH 74/85] GNRTA-370: ExpiringBlock for supernode_list request --- src/supernode/requests/debug.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/supernode/requests/debug.cpp b/src/supernode/requests/debug.cpp index 438cc232..b71e826d 100644 --- a/src/supernode/requests/debug.cpp +++ b/src/supernode/requests/debug.cpp @@ -25,6 +25,7 @@ GRAFT_DEFINE_IO_STRUCT(DbSupernode, (std::string, Address), (std::string, PublicId), (uint64, StakeAmount), + (uint64, ExpiringBlock), (uint64, LastUpdateAge) ); @@ -72,6 +73,7 @@ Status getSupernodeList(const Router::vars_t& vars, const graft::Input& input, dbSupernode.Address = sPtr->walletAddress(); dbSupernode.PublicId = sPtr->idKeyAsString(); dbSupernode.StakeAmount = sPtr->stakeAmount(); + dbSupernode.ExpiringBlock = sPtr->stakeBlockHeight() + sPtr->stakeUnlockTime(); resp.result.items.push_back(dbSupernode); } output.load(resp); From a593054072352bb64091c81c25c1e2b91b524de6 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 12 Mar 2019 20:34:33 -0300 Subject: [PATCH 75/85] Fix for single-core systems, part 2 --- src/lib/graft/task.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/graft/task.cpp b/src/lib/graft/task.cpp index af83d445..7197eb1b 100644 --- a/src/lib/graft/task.cpp +++ b/src/lib/graft/task.cpp @@ -843,7 +843,7 @@ void TaskManager::onClientDone(BaseTaskPtr bt) void TaskManager::initThreadPool(int threadCount, int workersQueueSize, int expellingIntervalMs) { if(threadCount <= 0) threadCount = std::thread::hardware_concurrency(); - threadCount = next_pow2(threadCount); + threadCount = std::max(size_t(2), next_pow2(threadCount)); if(workersQueueSize <= 0) workersQueueSize = 32; tp::ThreadPoolOptions th_op; From e398099b31e980d2dff9e473ec8bbd5c14ae2e6a Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 13 Mar 2019 22:49:33 +0300 Subject: [PATCH 76/85] auth sample size is 8 members --- include/rta/fullsupernodelist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index b835ac85..68f398fd 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -27,7 +27,7 @@ class FullSupernodeList { public: static constexpr int32_t TIERS = 4; - static constexpr int32_t ITEMS_PER_TIER = 1; + static constexpr int32_t ITEMS_PER_TIER = 2; static constexpr int32_t AUTH_SAMPLE_SIZE = TIERS * ITEMS_PER_TIER; static constexpr int64_t AUTH_SAMPLE_HASH_HEIGHT = 20; // block number for calculating auth sample should be calculated as current block height - AUTH_SAMPLE_HASH_HEIGHT; static constexpr int64_t ANNOUNCE_TTL_SECONDS = 60 * 60; // if more than ANNOUNCE_TTL_SECONDS passed from last annouce - supernode excluded from auth sample selection From 32e520febc21a10ab7278bc6d79345f44ffa26e7 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 13 Mar 2019 22:50:46 +0300 Subject: [PATCH 77/85] version bumb --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 51b2f6c0..8732f571 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define GRAFT_SUPERNODE_VERSION_TAG "@VERSIONTAG@" -#define GRAFT_SUPERNODE_VERSION "0.5.0" +#define GRAFT_SUPERNODE_VERSION "1.0.0" #define GRAFT_SUPERNODE_RELEASE_NAME "" #define GRAFT_SUPERNODE_VERSION_FULL GRAFT_SUPERNODE_VERSION "-" GRAFT_SUPERNODE_VERSION_TAG From 9d949a9e1dc508502e7cf64acb8042b75f22b081 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 13 Mar 2019 22:52:29 +0300 Subject: [PATCH 78/85] Updated cryptonode submodule --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index 3ad63e24..db25d507 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit 3ad63e24889e4671f68db70cb34cc2f09fa45b52 +Subproject commit db25d50797e6d914ea95841548c2b023b69436c2 From b315fae4078456f6742f247b4a6eb8fb876c1948 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Mar 2019 00:05:26 +0300 Subject: [PATCH 79/85] disabled rta code --- src/supernode/requests/authorize_rta_tx.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/supernode/requests/authorize_rta_tx.cpp b/src/supernode/requests/authorize_rta_tx.cpp index dabf299f..e38eebbd 100644 --- a/src/supernode/requests/authorize_rta_tx.cpp +++ b/src/supernode/requests/authorize_rta_tx.cpp @@ -114,6 +114,7 @@ struct RtaAuthResult // TODO: this function duplicates PendingTransaction::putRtaSignatures void putRtaSignaturesToTx(cryptonote::transaction &tx, const std::vector &signatures, bool testnet) { +#if 0 std::vector bin_signs; for (const auto &sign : signatures) { cryptonote::rta_signature bin_sign; @@ -125,6 +126,7 @@ void putRtaSignaturesToTx(cryptonote::transaction &tx, const std::vector Date: Thu, 14 Mar 2019 04:16:25 +0200 Subject: [PATCH 80/85] Check supernode availability in RTA Auth Sample --- src/rta/fullsupernodelist.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/rta/fullsupernodelist.cpp b/src/rta/fullsupernodelist.cpp index e7df51fa..2a92fb0c 100644 --- a/src/rta/fullsupernodelist.cpp +++ b/src/rta/fullsupernodelist.cpp @@ -288,9 +288,28 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym std::array tier_supernodes; { - blockchain_based_list_ptr blockchain_based_list = findBlockchainBasedList(blockchain_based_list_height); + blockchain_based_list_ptr bbl = std::make_shared(); + { + blockchain_based_list_ptr tmp_bbl = findBlockchainBasedList(blockchain_based_list_height); + for(blockchain_based_list_tier& src : *tmp_bbl) + { + blockchain_based_list_tier dst; + std::copy_if(src.begin(), src.end(), std::back_inserter(dst), [this](const auto& entry)->bool + { + auto it = m_list.find(entry.supernode_public_id); + if(it == m_list.end()) return false; + SupernodePtr& sn = it->second; + uint64_t lastUpdateAge = static_cast(std::time(nullptr)) - sn->lastUpdateTime(); + if(FullSupernodeList::ANNOUNCE_TTL_SECONDS < lastUpdateAge) return false; + return true; + }); + bbl->emplace_back(std::move(dst)); + } + } + + - if (!blockchain_based_list) + if (!bbl) { LOG_ERROR("unable to build auth sample for block height " << height << " (blockchain_based_list_height=" << blockchain_based_list_height << ") and PaymentID " << payment_id << ". Blockchain based list for this block is absent, latest block is " << getBlockchainBasedListMaxBlockNumber()); @@ -308,9 +327,9 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym //select supernodes for a full supernode list - MDEBUG("use blockchain based list for height " << blockchain_based_list_height << " (" << blockchain_based_list.get() << ")"); + MDEBUG("use blockchain based list for height " << blockchain_based_list_height << " (" << bbl.get() << ")"); int t = 0; - for (const blockchain_based_list_tier& l : *blockchain_based_list) + for (const blockchain_based_list_tier& l : *bbl) { MDEBUG("...tier #" << t); int j=0; @@ -319,9 +338,9 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym t++; } - for (size_t i=0, tiers_count=blockchain_based_list->size(); isize(); i Date: Thu, 14 Mar 2019 10:43:42 +0300 Subject: [PATCH 81/85] supernode announce ttl = 5 minutes --- include/rta/fullsupernodelist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 68f398fd..7669943a 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -30,7 +30,7 @@ class FullSupernodeList static constexpr int32_t ITEMS_PER_TIER = 2; static constexpr int32_t AUTH_SAMPLE_SIZE = TIERS * ITEMS_PER_TIER; static constexpr int64_t AUTH_SAMPLE_HASH_HEIGHT = 20; // block number for calculating auth sample should be calculated as current block height - AUTH_SAMPLE_HASH_HEIGHT; - static constexpr int64_t ANNOUNCE_TTL_SECONDS = 60 * 60; // if more than ANNOUNCE_TTL_SECONDS passed from last annouce - supernode excluded from auth sample selection + static constexpr int64_t ANNOUNCE_TTL_SECONDS = 5 * 60; // if more than ANNOUNCE_TTL_SECONDS passed from last annouce - supernode excluded from auth sample selection FullSupernodeList(const std::string &daemon_address, bool testnet = false); ~FullSupernodeList(); From 1173795ffe6eb37ad53a9bd32ae1fb7c88dd315b Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Mar 2019 10:53:27 +0300 Subject: [PATCH 82/85] updated cryptonode submodule --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index db25d507..fcfee7f6 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit db25d50797e6d914ea95841548c2b023b69436c2 +Subproject commit fcfee7f6a75ab689ec58611b248cb72e3665f434 From 4d50458fffa5be934ef8b8f8be496b0409814ef8 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Mar 2019 17:36:05 +0300 Subject: [PATCH 83/85] Revert "supernode announce ttl = 5 minutes" This reverts commit 11e7b2d5e1549b74c23e964993c3a352aa5f88d5. --- include/rta/fullsupernodelist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rta/fullsupernodelist.h b/include/rta/fullsupernodelist.h index 7669943a..68f398fd 100644 --- a/include/rta/fullsupernodelist.h +++ b/include/rta/fullsupernodelist.h @@ -30,7 +30,7 @@ class FullSupernodeList static constexpr int32_t ITEMS_PER_TIER = 2; static constexpr int32_t AUTH_SAMPLE_SIZE = TIERS * ITEMS_PER_TIER; static constexpr int64_t AUTH_SAMPLE_HASH_HEIGHT = 20; // block number for calculating auth sample should be calculated as current block height - AUTH_SAMPLE_HASH_HEIGHT; - static constexpr int64_t ANNOUNCE_TTL_SECONDS = 5 * 60; // if more than ANNOUNCE_TTL_SECONDS passed from last annouce - supernode excluded from auth sample selection + static constexpr int64_t ANNOUNCE_TTL_SECONDS = 60 * 60; // if more than ANNOUNCE_TTL_SECONDS passed from last annouce - supernode excluded from auth sample selection FullSupernodeList(const std::string &daemon_address, bool testnet = false); ~FullSupernodeList(); From ca6c8c8b6f15b766af5de0c15e5b8824b075c6fb Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Mar 2019 17:38:33 +0300 Subject: [PATCH 84/85] config: announce interval = 90 seconds --- data/config.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/config.ini b/data/config.ini index 89947ec6..dbc86429 100644 --- a/data/config.ini +++ b/data/config.ini @@ -29,7 +29,7 @@ lru-timeout-ms=60000 data-dir= stake-wallet-name=stake-wallet testnet=true -stake-wallet-refresh-interval-ms=50000 +stake-wallet-refresh-interval-ms=90000 stake-wallet-refresh-interval-random-factor=0 wallet-public-address= From 86190da921473edcfb4cd406b8ab076ab8887fa7 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Mar 2019 21:11:42 +0300 Subject: [PATCH 85/85] Updated cryptonode branch --- modules/cryptonode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryptonode b/modules/cryptonode index fcfee7f6..4637baeb 160000 --- a/modules/cryptonode +++ b/modules/cryptonode @@ -1 +1 @@ -Subproject commit fcfee7f6a75ab689ec58611b248cb72e3665f434 +Subproject commit 4637baebbd87ad46b25ffaac4339060f06aa374b