diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 6829b645..3f5aa31b 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -44,6 +44,18 @@ namespace net_utils { /************************************************************************/ DISABLE_VS_WARNINGS(4355) + + +template > +struct has_pre_destructor_handler : std::false_type {}; + +// This specialization is selected if T has a valid 'b()' that can be called +template +struct has_pre_destructor_handler().on_pre_destroy())>> + : std::true_type {}; + + + template connection::connection(boost::asio::io_service& io_service, typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter*& pfilter) @@ -66,6 +78,12 @@ connection::~connection() { NESTED_TRY_ENTRY(); + if constexpr (has_pre_destructor_handler::value) + { + m_protocol_handler.on_pre_destroy(); + } + + if(!m_was_shutdown) { LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown."); shutdown(); diff --git a/contrib/epee/include/net/levin_base.h b/contrib/epee/include/net/levin_base.h index 4f55b0df..3d7e927d 100644 --- a/contrib/epee/include/net/levin_base.h +++ b/contrib/epee/include/net/levin_base.h @@ -33,6 +33,25 @@ #define LEVIN_SIGNATURE 0x0101010101012101LL //Bender's nightmare + + +#define LEVIN_OK 0 +#define LEVIN_ERROR_CONNECTION -1 +#define LEVIN_ERROR_CONNECTION_NOT_FOUND -2 +#define LEVIN_ERROR_CONNECTION_DESTROYED -3 +#define LEVIN_ERROR_CONNECTION_TIMEDOUT -4 +#define LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL -5 +#define LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED -6 +#define LEVIN_ERROR_FORMAT -7 +#define LEVIN_ERROR_EXCEPTION -8 +#define LEVIN_ERROR_UNKNOWN_ERROR -9 +#define LEVIN_ERROR_INTERNAL -10 +#define LEVIN_ERROR_PROTOCOL_INCONSISTENT -11 +#define LEVIN_ERROR_NET_ERROR -12 +#define LEVIN_ERROR_SIGNATURE_MISMATCH -13 + + + namespace epee { namespace levin @@ -86,23 +105,15 @@ namespace levin virtual void on_connection_new(t_connection_context& context){}; virtual void on_connection_close(t_connection_context& context){}; - }; -#define LEVIN_OK 0 -#define LEVIN_ERROR_CONNECTION -1 -#define LEVIN_ERROR_CONNECTION_NOT_FOUND -2 -#define LEVIN_ERROR_CONNECTION_DESTROYED -3 -#define LEVIN_ERROR_CONNECTION_TIMEDOUT -4 -#define LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL -5 -#define LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED -6 -#define LEVIN_ERROR_FORMAT -7 -#define LEVIN_ERROR_EXCEPTION -8 -#define LEVIN_ERROR_UNKNOWN_ERROR -9 -#define LEVIN_ERROR_INTERNAL -10 -#define LEVIN_ERROR_PROTOCOL_INCONSISTENT -11 -#define LEVIN_ERROR_NET_ERROR -12 -#define LEVIN_ERROR_SIGNATURE_MISMATCH -13 + template + struct levin_commands_handler_dummy: public levin_commands_handler + { + virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, t_connection_context& context) { return LEVIN_OK; } + virtual int notify(int command, const std::string& in_buff, t_connection_context& context) { return LEVIN_OK; } + }; + #define DESCRIBE_RET_CODE(code) case code: return #code; inline diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index c3cdd02d..d2c536ba 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -59,6 +59,7 @@ class async_protocol_handler_config critical_section m_connects_lock; std::atomic m_is_in_sendstop_loop; connections_map m_connects; + levin_commands_handler_dummy m_commands_handler_dummy; void add_connection(async_protocol_handler* pc); void del_connection(async_protocol_handler* pc); @@ -87,7 +88,7 @@ public: bool foreach_connection(callback_t cb); size_t get_connections_count(); - async_protocol_handler_config() :m_pcommands_handler(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE), m_is_in_sendstop_loop(false), m_invoke_timeout{} + async_protocol_handler_config() :m_pcommands_handler(&m_commands_handler_dummy), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE), m_is_in_sendstop_loop(false), m_invoke_timeout{} {} ~async_protocol_handler_config() { @@ -252,6 +253,7 @@ public: LOG_PRINT_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "] CONSTRUCTED", LOG_LEVEL_4); } + virtual ~async_protocol_handler() { NESTED_TRY_ENTRY(); @@ -278,6 +280,11 @@ public: NESTED_CATCH_ENTRY(__func__); } + void on_pre_destroy() + { + m_config.del_connection(this); + } + bool start_outer_call() { LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] -->> start_outer_call"); diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h index 9971ef12..73f84b15 100644 --- a/contrib/epee/include/syncobj.h +++ b/contrib/epee/include/syncobj.h @@ -277,7 +277,7 @@ namespace epee #define POTENTIAL_HANG_PREVENT_LIMIT 1000 - +#define DEADLOCK_GUARD_JOURNAL_LIMIT 1000 /************************************************************************/ /* */ @@ -290,11 +290,11 @@ namespace epee struct thread_info { std::map m_owned_objects; - bool is_blocked; - lock_reference_type blocker_lock; - const char* block_location; - const char* func_name; - const char* lock_name; + bool is_blocked = false; + lock_reference_type blocker_lock = nullptr; + const char* block_location = "unknown"; + const char* func_name = "unknown"; + const char* lock_name = "unknown"; std::string thread_name; }; @@ -307,6 +307,18 @@ namespace epee std::map m_owned_locks_to_thread; // deadlock journal std::list m_deadlock_journal; + //lock/unlock journal + struct journal_entry + { + std::thread::id tid; + lock_reference_type lock = nullptr; + bool is_lock_event = false; + const char* func_name = "unkonwn"; + const char* lock_name = "unkonwn"; + std::string thread_name; + }; + + std::list m_journal; public: void on_before_lock(lock_reference_type lock, const char* func_name, const char* loction, const char* lock_name, const std::string& thread_name) @@ -363,6 +375,10 @@ namespace epee } else { + m_journal.push_front(journal_entry{ this_id, lock, false, "", "", ""}); + if (m_journal.size() > DEADLOCK_GUARD_JOURNAL_LIMIT) + m_journal.pop_back(); + m_owned_locks_to_thread.erase(lock_to_thread_it); } it->second.m_owned_objects.erase(ownership_it); @@ -400,6 +416,15 @@ namespace epee ss << "-----------------------------------------------------------------------" << std::endl << err << std::endl; } + ss << "Ownership history history:" << std::endl; + size_t count = 0; + for (auto entry : m_journal) + { + ss << "tid(" << entry.thread_name << "): " << entry.tid << ", lock_addr: " << entry.lock << (entry.is_lock_event ? "-->":"<--") << ", func: " << (entry.func_name ? entry.func_name:"") << ", lock_name: " << (entry.lock_name ? entry.lock_name : "") << std::endl; + if (++count > 100) + break; + } + return ss.str(); } @@ -429,6 +454,10 @@ namespace epee //need to add lock-to-thread reccord m_owned_locks_to_thread[lock] = it; DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][ADDED_OWNERSHIP]: " << lock << std::endl); + m_journal.push_front(journal_entry{ this_id, lock, true, it->second.func_name, it->second.lock_name, it->second.thread_name }); + if (m_journal.size() > DEADLOCK_GUARD_JOURNAL_LIMIT) + m_journal.pop_back(); + } else { diff --git a/src/common/pre_download.h b/src/common/pre_download.h index c44649a0..9314c059 100644 --- a/src/common/pre_download.h +++ b/src/common/pre_download.h @@ -59,7 +59,7 @@ namespace tools } // okay, let's download - + LOG_PRINT_MAGENTA("Pre-download required: local db size: " << sz << ", pre_download.unpacked_size = " << pre_download.unpacked_size << ", flag_force_predownload: " << (flag_force_predownload ? "true":"false"), LOG_LEVEL_0); std::string downloading_file_path = db_main_file_path + ".download"; if (!command_line::has_arg(vm, command_line::arg_process_predownload_from_path)) { diff --git a/src/wallet/wallet_chain_shortener.cpp b/src/currency_core/block_chain_shortener.cpp similarity index 70% rename from src/wallet/wallet_chain_shortener.cpp rename to src/currency_core/block_chain_shortener.cpp index 39d37c75..d9aa9d49 100644 --- a/src/wallet/wallet_chain_shortener.cpp +++ b/src/currency_core/block_chain_shortener.cpp @@ -4,19 +4,19 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "wallet_chain_shortener.h" -#include "wallet_errors.h" +#include "block_chain_shortener.h" +//#include "wallet_errors.h" -#define WALLET_EVERYBLOCK_SIZE 20 -#define WALLET_EVERY_10_BLOCKS_SIZE 144 -#define WALLET_EVERY_100_BLOCKS_SIZE 144 -#define WALLET_EVERY_1000_BLOCKS_SIZE 144 +#define SHORTENER_EVERYBLOCK_SIZE 20 +#define SHORTENER_EVERY_10_BLOCKS_SIZE 144 +#define SHORTENER_EVERY_100_BLOCKS_SIZE 144 +#define SHORTENER_EVERY_1000_BLOCKS_SIZE 144 static void exception_handler(){} -void wallet_chain_shortener::clear() +void block_chain_shortener::clear() { m_local_bc_size = 1; m_last_20_blocks.clear(); @@ -26,29 +26,42 @@ void wallet_chain_shortener::clear() } //---------------------------------------------------------------------------------------------------- -uint64_t wallet_chain_shortener::get_blockchain_current_size() const +uint64_t block_chain_shortener::get_blockchain_current_size() const { return m_local_bc_size; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet_chain_shortener::get_top_block_height() const +uint64_t block_chain_shortener::get_top_block_height() const { return m_local_bc_size - 1; } //---------------------------------------------------------------------------------------------------- -void wallet_chain_shortener::set_genesis(const crypto::hash& id) +crypto::hash block_chain_shortener::get_top_block_id() const +{ + if (m_last_20_blocks.size()) + return (--m_last_20_blocks.end())->second; + + else return currency::null_hash; +} +//---------------------------------------------------------------------------------------------------- +void block_chain_shortener::set_genesis(const crypto::hash& id) { m_genesis = id; m_local_bc_size = 1; } //---------------------------------------------------------------------------------------------------- -const crypto::hash& wallet_chain_shortener::get_genesis() +const crypto::hash& block_chain_shortener::get_genesis() { return m_genesis; } //---------------------------------------------------------------------------------------------------- -void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t height) +void block_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t height) { + if (height < m_local_bc_size) + { + detach(height); + } + if (height == 0) { m_genesis = id; @@ -60,12 +73,13 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t //self check if (m_local_bc_size != 1) { - THROW_IF_FALSE_WALLET_INT_ERR_EX(get_blockchain_current_size() == height, "Inernal error: get_blockchain_current_height(){" << get_blockchain_current_size() << "} == height{" << height << "} is not equal"); + CHECK_AND_ASSERT_THROW_MES(get_blockchain_current_size() == height, "Inernal error: get_blockchain_current_height(){" << get_blockchain_current_size() << "} == height{" << height << "} is not equal") + //THROW_IF_FALSE_INT_ERR_EX(); } m_local_bc_size = height+1; m_last_20_blocks[height] = id; - if (m_last_20_blocks.size() > WALLET_EVERYBLOCK_SIZE) + if (m_last_20_blocks.size() > SHORTENER_EVERYBLOCK_SIZE) { m_last_20_blocks.erase(m_last_20_blocks.begin()); } @@ -76,10 +90,10 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t //self check if (!m_last_144_blocks_every_10.empty()) { - THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_144_blocks_every_10.end())->first + 10 == height, "Inernal error: (--m_last_144_blocks_every_10.end())->first + 10{" << (--m_last_144_blocks_every_10.end())->first + 10 << "} == height{" << height << "} is not equal"); + CHECK_AND_ASSERT_THROW_MES((--m_last_144_blocks_every_10.end())->first + 10 == height, "Inernal error: (--m_last_144_blocks_every_10.end())->first + 10{" << (--m_last_144_blocks_every_10.end())->first + 10 << "} == height{" << height << "} is not equal"); } m_last_144_blocks_every_10[height] = id; - if (m_last_144_blocks_every_10.size() > WALLET_EVERY_10_BLOCKS_SIZE) + if (m_last_144_blocks_every_10.size() > SHORTENER_EVERY_10_BLOCKS_SIZE) { m_last_144_blocks_every_10.erase(m_last_144_blocks_every_10.begin()); } @@ -90,10 +104,10 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t //self check if (!m_last_144_blocks_every_100.empty()) { - THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_144_blocks_every_100.end())->first + 100 == height, "Inernal error: (--m_last_144_blocks_every_100.end())->first + 100{" << (--m_last_144_blocks_every_100.end())->first + 100 << "} == height{" << height << "} is not equal"); + CHECK_AND_ASSERT_THROW_MES((--m_last_144_blocks_every_100.end())->first + 100 == height, "Inernal error: (--m_last_144_blocks_every_100.end())->first + 100{" << (--m_last_144_blocks_every_100.end())->first + 100 << "} == height{" << height << "} is not equal"); } m_last_144_blocks_every_100[height] = id; - if (m_last_144_blocks_every_100.size() > WALLET_EVERY_100_BLOCKS_SIZE) + if (m_last_144_blocks_every_100.size() > SHORTENER_EVERY_100_BLOCKS_SIZE) { m_last_144_blocks_every_100.erase(m_last_144_blocks_every_100.begin()); } @@ -105,10 +119,10 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t //self check if (!m_last_144_blocks_every_1000.empty()) { - THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_144_blocks_every_1000.end())->first + 1000 == height, "Inernal error: (--m_last_144_blocks_every_1000.end())->first + 1000{" << (--m_last_144_blocks_every_1000.end())->first + 1000 << "} == height{" << height << "} is not equal"); + CHECK_AND_ASSERT_THROW_MES((--m_last_144_blocks_every_1000.end())->first + 1000 == height, "Inernal error: (--m_last_144_blocks_every_1000.end())->first + 1000{" << (--m_last_144_blocks_every_1000.end())->first + 1000 << "} == height{" << height << "} is not equal"); } m_last_144_blocks_every_1000[height] = id; - if (m_last_144_blocks_every_1000.size() > WALLET_EVERY_1000_BLOCKS_SIZE) + if (m_last_144_blocks_every_1000.size() > SHORTENER_EVERY_1000_BLOCKS_SIZE) { m_last_144_blocks_every_1000.erase(m_last_144_blocks_every_1000.begin()); } @@ -118,7 +132,7 @@ void wallet_chain_shortener::push_new_block_id(const crypto::hash& id, uint64_t } //---------------------------------------------------------------------------------------------------- -void wallet_chain_shortener::get_short_chain_history(std::list& ids)const +void block_chain_shortener::get_short_chain_history(std::list& ids)const { ids.clear(); uint64_t i = 0; @@ -137,7 +151,7 @@ void wallet_chain_shortener::get_short_chain_history(std::list& id uint64_t current_back_offset = ids.size()+1; //self check - THROW_IF_FALSE_WALLET_INT_ERR_EX(current_back_offset == sz - i + 1 || !count, "Inernal error: current_back_offset{" << current_back_offset << "} == sz-i{" << sz << " - " << i << "} is not equal"); + CHECK_AND_ASSERT_THROW_MES(current_back_offset == sz - i + 1 || !count, "Inernal error: current_back_offset{" << current_back_offset << "} == sz-i{" << sz << " - " << i << "} is not equal"); uint64_t current_offset_distance = 1; while (current_back_offset < sz) @@ -157,7 +171,7 @@ void wallet_chain_shortener::get_short_chain_history(std::list& id ids.push_back(m_genesis); } //---------------------------------------------------------------------------------------------------- -bool wallet_chain_shortener::lookup_item_around(uint64_t i, std::pair& result)const +bool block_chain_shortener::lookup_item_around(uint64_t i, std::pair& result)const { //in which container we are looking for? uint64_t devider = 0; @@ -189,14 +203,14 @@ bool wallet_chain_shortener::lookup_item_around(uint64_t i, std::pairfind(i); //self check - THROW_IF_FALSE_WALLET_INT_ERR_EX(it != pcontainer->end(), + CHECK_AND_ASSERT_THROW_MES(it != pcontainer->end(), "Inernal error: index " << i << " not found for devider " << devider << " pcontainer={" << pcontainer->begin()->first << ":" << (--pcontainer->end())->first << "}"); result = *it; return true; } //---------------------------------------------------------------------------------------------------- -void wallet_chain_shortener::check_if_block_matched(uint64_t i, const crypto::hash& id, bool& block_found, bool& block_matched, bool& full_reset_needed)const +void block_chain_shortener::check_if_block_matched(uint64_t i, const crypto::hash& id, bool& block_found, bool& block_matched, bool& full_reset_needed)const { if (i == 0) { @@ -221,12 +235,12 @@ void wallet_chain_shortener::check_if_block_matched(uint64_t i, const crypto::ha { //must be in short sequence (m_last_20_blocks) //self check - THROW_IF_FALSE_WALLET_INT_ERR_EX((--m_last_20_blocks.end())->first >= i, + CHECK_AND_ASSERT_THROW_MES((--m_last_20_blocks.end())->first >= i, "Inernal error: index " << i << " is not located in expected range of m_last_20_blocks={" << m_last_20_blocks.begin()->first << ":" << (--m_last_20_blocks.end())->first << "}"); auto it = m_last_20_blocks.find(i); - THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_last_20_blocks.end(), + CHECK_AND_ASSERT_THROW_MES(it != m_last_20_blocks.end(), "Inernal error: filde to find index " << i << " in m_last_20_blocks={" << m_last_20_blocks.begin()->first << ":" << (--m_last_20_blocks.end())->first << "}"); @@ -271,7 +285,7 @@ void wallet_chain_shortener::check_if_block_matched(uint64_t i, const crypto::ha } } //---------------------------------------------------------------------------------------------------- -std::string wallet_chain_shortener::get_internal_state_text() const +std::string block_chain_shortener::get_internal_state_text() const { std::stringstream ss; #define PRINT_CHAIN_SHORTENER_STATE_INFO(cont_name) \ @@ -296,7 +310,7 @@ void clean_map_from_items_above(std::map& container, uin } } //---------------------------------------------------------------------------------------------------- -void wallet_chain_shortener::detach(uint64_t including_height) +void block_chain_shortener::detach(uint64_t including_height) { clean_map_from_items_above(m_last_20_blocks, including_height); clean_map_from_items_above(m_last_144_blocks_every_10, including_height); diff --git a/src/wallet/wallet_chain_shortener.h b/src/currency_core/block_chain_shortener.h similarity index 96% rename from src/wallet/wallet_chain_shortener.h rename to src/currency_core/block_chain_shortener.h index a5e66a9a..dfd64de1 100644 --- a/src/wallet/wallet_chain_shortener.h +++ b/src/currency_core/block_chain_shortener.h @@ -19,11 +19,12 @@ #include "crypto/crypto.h" #include "currency_core/currency_basic.h" -class wallet_chain_shortener +class block_chain_shortener { public: void push_new_block_id(const crypto::hash& id, uint64_t height); uint64_t get_top_block_height() const; + crypto::hash get_top_block_id() const; uint64_t get_blockchain_current_size() const; void get_short_chain_history(std::list& ids)const; bool lookup_item_around(uint64_t i, std::pair& result)const; diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 0c4ed2a2..64fa2537 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -3762,6 +3762,22 @@ bool blockchain_storage::have_block(const crypto::hash& id)const return false; } //------------------------------------------------------------------ +bool blockchain_storage::have_block_main(const crypto::hash& id) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (m_db_blocks_index.find(id)) + return true; + return false; +} +//------------------------------------------------------------------ +bool blockchain_storage::have_block_alt(const crypto::hash& id) const +{ + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + if (m_alternative_chains.count(id)) + return true; + return false; +} +//------------------------------------------------------------------ bool blockchain_storage::handle_block_to_main_chain(const block& bl, block_verification_context& bvc) { crypto::hash id = get_block_hash(bl); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 31211aed..d9b2096e 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -283,6 +283,8 @@ namespace currency bool create_block_template(const create_block_template_params& params, create_block_template_response& resp) const; bool have_block(const crypto::hash& id) const; + bool have_block_main(const crypto::hash& id) const; + bool have_block_alt(const crypto::hash& id) const; size_t get_total_transactions()const; bool get_outs(uint64_t amount, std::list& pkeys)const; bool get_short_chain_history(std::list& ids)const; diff --git a/src/currency_core/connection_context.h b/src/currency_core/connection_context.h index 1320619c..43f372c5 100644 --- a/src/currency_core/connection_context.h +++ b/src/currency_core/connection_context.h @@ -9,6 +9,7 @@ #include #include "net/net_utils_base.h" #include "copyable_atomic.h" +#include "block_chain_shortener.h" namespace currency { @@ -33,7 +34,8 @@ namespace currency std::list m_needed_objects; std::unordered_set m_requested_objects; std::atomic m_callback_request_count; //in debug purpose: problem with double callback rise - + // + block_chain_shortener m_last_fetched_block_ids; }; struct currency_connection_context: public epee::net_utils::connection_context_base diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index 94b77505..86abbfd1 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -744,10 +744,40 @@ namespace currency {//we have to fetch more objects ids, request blockchain entry NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized(); - m_core.get_short_chain_history(r.block_ids); - LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); - LOG_PRINT_L3("[NOTIFY]NOTIFY_REQUEST_CHAIN: " << ENDL << print_kv_structure(r) ); + if (context.m_priv.m_last_fetched_block_ids.get_top_block_height() > 0) + { + bool last_received_block_is_in_mainchain = m_core.get_blockchain_storage().have_block_main(context.m_priv.m_last_fetched_block_ids.get_top_block_id()); + bool far_from_top = context.m_priv.m_last_fetched_block_ids.get_top_block_height() + BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT < m_core.get_blockchain_storage().get_current_blockchain_size(); + if (!last_received_block_is_in_mainchain || (last_received_block_is_in_mainchain && far_from_top)) + { + block_extended_info blk = AUTO_VAL_INIT(blk); + // In this scenario, it's likely the remote daemon is on an alternate chain + // where the network split goes deeper than 2000 blocks. The NOTIFY_REQUEST_GET_OBJECTS + // call returns a batch of BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT IDs, which may + // start well beyond the original split point. + // + // If we repeatedly call NOTIFY_REQUEST_GET_OBJECTS with the IDs obtained from + // get_short_chain_history, it would create an endless loop. However, we still need + // to retrieve the full alternate chain from the remote daemon because it could + // potentially be “heavier” (in terms of consensus). + // + // Therefore, we provide only the last ten blocks returned by the remote daemon + // in the NOTIFY_REQUEST_CHAIN request, expecting to receive the subsequent batch + // of alternate blocks next. + context.m_priv.m_last_fetched_block_ids.get_short_chain_history(r.block_ids); + //add genesis to the latest + LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_CHAIN: requesting alt version starting from " << r.block_ids.front()); + } + } + + if (!r.block_ids.size()) + { + m_core.get_short_chain_history(r.block_ids); + } + LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size()); + LOG_PRINT_L3("[NOTIFY]NOTIFY_REQUEST_CHAIN: " << ENDL << print_kv_structure(r)); post_notify(r, context); + }else { CHECK_AND_ASSERT_MES(context.m_last_response_height == context.m_remote_blockchain_height-1 @@ -976,10 +1006,16 @@ namespace currency m_p2p->add_ip_fail(context.m_remote_ip); } + uint64_t height = arg.start_height; BOOST_FOREACH(auto& bl_details, arg.m_block_ids) { if (!m_core.have_block(bl_details.h)) + { context.m_priv.m_needed_objects.push_back(bl_details); + } + + context.m_priv.m_last_fetched_block_ids.push_new_block_id(bl_details.h, height); + height++; } request_missing_objects(context, false); diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 67bba659..8c0f9efd 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -69,6 +69,7 @@ namespace plain_wallet std::atomic initialized = false; std::atomic postponed_run_wallet = false; std::atomic postponed_main_worked_started = false; + callback_type m_callback = nullptr; std::atomic gjobs_counter; std::map gjobs; @@ -565,11 +566,28 @@ namespace plain_wallet { return; } - CRITICAL_REGION_LOCAL(inst_ptr->gjobs_lock); - inst_ptr->gjobs[job_id] = res; - LOG_PRINT_L2("[ASYNC_CALL]: Finished(result put), job id: " << job_id); + if (inst_ptr->m_callback) + { + inst_ptr->m_callback(job_id, res); + LOG_PRINT_L2("[ASYNC_CALL]: Finished(result caalback), job id: " << job_id); + } + else + { + CRITICAL_REGION_LOCAL(inst_ptr->gjobs_lock); + inst_ptr->gjobs[job_id] = res; + LOG_PRINT_L2("[ASYNC_CALL]: Finished(result put), job id: " << job_id); + } } + void set_callback(callback_type callback) + { + auto inst_ptr = std::atomic_load(&ginstance_ptr); + if (!inst_ptr) + { + return; + } + inst_ptr->m_callback = callback; + } std::string async_call(const std::string& method_name, uint64_t instance_id, const std::string& params) { diff --git a/src/wallet/plain_wallet_api.h b/src/wallet/plain_wallet_api.h index 652e5f92..410a5c48 100644 --- a/src/wallet/plain_wallet_api.h +++ b/src/wallet/plain_wallet_api.h @@ -47,6 +47,10 @@ namespace plain_wallet std::string get_wallet_info(hwallet h); std::string reset_wallet_password(hwallet h, const std::string& password); uint64_t get_current_tx_fee(uint64_t priority); // 0 (default), 1 (unimportant), 2 (normal), 3 (elevated), 4 (priority) + + + typedef void (*callback_type)(uint64_t job_id, const std::string& job_response); + void set_callback(callback_type callback); } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index d5d3602b..a1274d6a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -41,7 +41,7 @@ #include "currency_core/bc_offers_serialization.h" #include "currency_core/bc_escrow_service.h" #include "common/pod_array_file_container.h" -#include "wallet_chain_shortener.h" +#include "currency_core/block_chain_shortener.h" #include "tor-connect/torlib/tor_lib_iface.h" #include "currency_core/pos_mining.h" #include "view_iface.h" @@ -127,7 +127,7 @@ namespace tools */ struct wallet2_base_state { - wallet_chain_shortener m_chain; + block_chain_shortener m_chain; uint64_t m_minimum_height = WALLET_MINIMUM_HEIGHT_UNSET_CONST; amount_gindex_to_transfer_id_container m_amount_gindex_to_transfer_id; transfer_container m_transfers; diff --git a/src/wallet/wallet2_base.h b/src/wallet/wallet2_base.h index e17b7d2e..d991a55b 100644 --- a/src/wallet/wallet2_base.h +++ b/src/wallet/wallet2_base.h @@ -39,7 +39,7 @@ #include "currency_core/bc_offers_serialization.h" #include "currency_core/bc_escrow_service.h" #include "common/pod_array_file_container.h" -#include "wallet_chain_shortener.h" +#include "currency_core/block_chain_shortener.h" #include "tor-connect/torlib/tor_lib_iface.h" #include "currency_core/pos_mining.h" #include "view_iface.h" diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 8521a399..38e4e1c5 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -43,7 +43,7 @@ void test_plain_wallet() plain_wallet::configure_object conf = AUTO_VAL_INIT(conf); //plain_wallet::configure_response conf_resp = AUTO_VAL_INIT(conf_resp); - conf.postponed_run_wallet = true; + //conf.postponed_run_wallet = true; std::string r = plain_wallet::sync_call("configure", 0, epee::serialization::store_t_to_json(conf)); @@ -77,6 +77,10 @@ void test_plain_wallet() //res = plain_wallet::sync_call("reset_connection_url", 0, "195.201.107.230:33336"); //res = plain_wallet::sync_call("reset_connection_url", 0, "https://node.zano.org:443"); + //res = plain_wallet::sync_call("reset_connection_url", 0, "https://zano.cakewallet.com"); + //res = plain_wallet::sync_call("reset_connection_url", 0, "https://zano.api.wombat.systems:443"); + //res = plain_wallet::sync_call("reset_connection_url", 0, "http://127.0.0.1:11211"); + r = plain_wallet::sync_call("run_wallet", instance_id, ""); diff --git a/tests/unit_tests/wallet_chain_shortener_test.cpp b/tests/unit_tests/wallet_chain_shortener_test.cpp index f814bcf0..8e0c1592 100644 --- a/tests/unit_tests/wallet_chain_shortener_test.cpp +++ b/tests/unit_tests/wallet_chain_shortener_test.cpp @@ -4,12 +4,12 @@ #include #include "gtest/gtest.h" -#include "wallet/wallet_chain_shortener.h" +#include "currency_core/block_chain_shortener.h" -TEST(wallet_chain_shortener, wallet_chain_shortener) +TEST(block_chain_shortener, block_chain_shortener) { uint64_t counter = 0; - wallet_chain_shortener ws; + block_chain_shortener ws; for (counter = 1; counter != 1000000; counter++) { diff --git a/utils/update_alert.json b/utils/update_alert.json index 90926d50..6025f950 100644 --- a/utils/update_alert.json +++ b/utils/update_alert.json @@ -1,11 +1,11 @@ { - "maj":1, - "min":0, + "maj":2, + "min":1, "rev":0, - "build":40, + "build":382, "cs":[ { - "build":40, + "build":382, "mode":3 } ]