From 9c21c114aaec6f6cb5f033b4cfe5afc3b715ae2d Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 17 Oct 2019 14:03:17 +0300 Subject: [PATCH 01/14] performance tests: free space check test improvements --- tests/performance_tests/free_space_check.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/performance_tests/free_space_check.h b/tests/performance_tests/free_space_check.h index 16ea0afb..f7fb2d5c 100644 --- a/tests/performance_tests/free_space_check.h +++ b/tests/performance_tests/free_space_check.h @@ -49,6 +49,7 @@ void free_space_check() boost::filesystem::path current_path("."); size_t counter = 0; + bool need_backspace = false; while (true) { std::this_thread::sleep_for(std::chrono::milliseconds( 900 )); @@ -59,26 +60,37 @@ void free_space_check() { // free space is ok counter = (counter + 1) % 4; - std::cout << '\b'; + if (need_backspace) + std::cout << '\b'; std::cout << ( counter == 0 ? '*' : counter == 1 ? '\\' : counter == 2 ? '|' : '/' ); + std::cout << std::flush; + need_backspace = true; continue; } // free space is not ok! - LOG_PRINT_YELLOW("free space available: " << si.available, LOG_LEVEL_0); + LOG_PRINT_YELLOW("1) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0); #ifdef WIN32 output = exec("dir"); #else output = exec("df -h"); #endif LOG_PRINT_YELLOW(output, LOG_LEVEL_0); + + // try one again asap + si = fs::space(current_path); + LOG_PRINT_YELLOW("2) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0); + + need_backspace = false; } catch (std::exception& e) { LOG_ERROR("failed to determine free space: " << e.what()); + need_backspace = false; } catch (...) { LOG_ERROR("failed to determine free space: unknown exception"); + need_backspace = false; } } From 87a294e58bcc4048952a9720fff74a8594224f80 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 17 Oct 2019 14:04:13 +0300 Subject: [PATCH 02/14] coretests: tx_key_image_pool_conflict improved to cover more cases, comments added --- tests/core_tests/tx_validation.cpp | 66 ++++++++++++++++-------------- tests/core_tests/tx_validation.h | 4 -- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index a71dae24..9833d5ef 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1453,14 +1453,13 @@ bool tx_expiration_time_and_chain_switching::generate(std::vector& events) const { + // Test idea: check tx that is stuck in tx pool because one on its key images is already spent in the blockchain + // 1) if it's linked to an alt block -- tx will not be removed as long as linked alt block exists (in order to be able to switch) + // 2) if it's not linked to an alt block -- it will be removed after CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL confirmations of conflicted tx + // or it will be removed once tx is old enough (CURRENCY_MEMPOOL_TX_LIVETIME) + bool r = false; m_miner_acc.generate(); @@ -1534,44 +1533,49 @@ bool tx_key_image_pool_conflict::generate(std::vector& events) // however, it does not remove tx from the pool DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + // + // make sure stuck tx will be removed from the pool when it's too old + // + MAKE_NEXT_BLOCK(events, blk_2, blk_1, m_miner_acc); - DO_CALLBACK(events, "remove_stuck_txs"); - // remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool + DO_CALLBACK(events, "remove_stuck_txs"); DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); // shift time by CURRENCY_MEMPOOL_TX_LIVETIME events.push_back(event_core_time(CURRENCY_MEMPOOL_TX_LIVETIME + 1, true)); - // remove_stuck_txs should remove only tx_2 and left tx_1 + // remove_stuck_txs should have removed tx_2 because it's too old DO_CALLBACK(events, "remove_stuck_txs"); + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(1)); + // + // make sure stuck tx will be removed from the pool as soon as one of its key images is spent deep enough in the blockchain + // (even if it's not too old to be removed by age) + // + + MAKE_NEXT_BLOCK(events, blk_3, blk_2, m_miner_acc); + + // re-add tx_2 with kept_by_block flag + events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true)); + events.push_back(tx_2); + events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false)); + + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + + // remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool + DO_CALLBACK(events, "remove_stuck_txs"); + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + + // rewind 50 blocks so tx_0 spending its key image will be deep enough + REWIND_BLOCKS_N_WITH_TIME(events, blk_3r, blk_3, m_miner_acc, 50); + + // remove_stuck_txs should remove only tx_2 and left tx_1 (linked to alt block) + DO_CALLBACK(events, "remove_stuck_txs"); DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(1)); DO_CALLBACK(events, "print_tx_pool"); return true; } - -bool tx_key_image_pool_conflict::c1(currency::core& c, size_t ev_index, const std::vector& events) -{ - bool r = false; - - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "incorrect tx pool count = " << c.get_pool_transactions_count()); - - // try to mine a block and make sure tx_1 is still in the pool (was not added to the blocktemplate) - block b; - r = mine_next_pow_block_in_playtime(m_miner_acc.get_public_address(), c, &b); - CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - - // make sure tx_1 is still here - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "incorrect tx pool count = " << c.get_pool_transactions_count()); - - return true; -} - -bool tx_key_image_pool_conflict::c2(currency::core& c, size_t ev_index, const std::vector& events) -{ - return true; -} diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 5c8bb524..c72ac866 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -150,10 +150,6 @@ struct tx_expiration_time_and_chain_switching : public test_chain_unit_enchanced struct tx_key_image_pool_conflict : public test_chain_unit_enchanced { - tx_key_image_pool_conflict(); bool generate(std::vector& events) const; - bool c1(currency::core& c, size_t ev_index, const std::vector& events); - bool c2(currency::core& c, size_t ev_index, const std::vector& events); - mutable currency::account_base m_miner_acc; }; From 2ba3f5afacbc2ce2d07df9de4cdfb6b0af19b0cb Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 17 Oct 2019 14:07:32 +0300 Subject: [PATCH 03/14] tx pool: remove stuck txs with key image conflicts from pool once conflicted tx has enough confirmations in the blockchain (closes #52) --- src/currency_core/tx_pool.cpp | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp index 440bd9a7..e773ad31 100644 --- a/src/currency_core/tx_pool.cpp +++ b/src/currency_core/tx_pool.cpp @@ -32,6 +32,8 @@ DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated #define TRANSACTION_POOL_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 92 // DON'T CHANGE THIS, if you need to resync db! Change TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION instead! #define TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 1 +#define CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL 50 // if there's a conflict in key images between tx in the pool and in the blockchain this much depth in required to remove correspongin tx from pool + #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "tx_pool" ENABLE_CHANNEL_BY_DEFAULT("tx_pool"); @@ -427,18 +429,41 @@ namespace currency int64_t tx_age = get_core_time() - tx_entry.receive_time; if ((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME )) { - - LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: outdated, age: " << tx_age); + LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: outdated, age: " << tx_age << " = " << misc_utils::get_time_interval_string(tx_age)); to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block)); } // expiration time check - remove expired if (is_tx_expired(tx_entry.tx, tx_expiration_ts_median) ) { - LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median); + LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median); to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block)); } + // if a tx has at least one key image already used in blockchain (deep enough) -- remove such tx, as it cannot be added to any block + // although it will be removed by the age check above, we consider desireable + // to remove it from the pool faster in order to unblock related key images used in the same tx + uint64_t should_be_spent_before_height = m_blockchain.get_current_blockchain_size() - 1; + if (should_be_spent_before_height > CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL) + { + should_be_spent_before_height -= CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL; + for (auto& in : tx_entry.tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + // if at least one key image is spent deep enought -- remove such tx + const crypto::key_image& ki = boost::get(in).k_image; + if (m_blockchain.have_tx_keyimg_as_spent(ki, should_be_spent_before_height)) + { + LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: ki was spent in the blockchain before height " << should_be_spent_before_height << ", tx age: " << misc_utils::get_time_interval_string(tx_age)); + to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block)); + return true; + } + } + } + } + + return true; }); From 9d829d2cb39c8b619aa1dfbe5ac363146d67a4bd Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 18 Oct 2019 18:56:20 +0300 Subject: [PATCH 04/14] === build number: 67 -> 68 === --- 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 bbd5c6c5..80faa1a2 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "2" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 67 +#define PROJECT_VERSION_BUILD_NO 68 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" From b398de6e9f0c0a8c5e20ec47460190924e03347b Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 19 Oct 2019 06:38:21 +0300 Subject: [PATCH 05/14] minor log improvements in currency protocol and epee's net_utils_base --- contrib/epee/include/net/net_utils_base.h | 26 +++++++++--------- .../currency_protocol_handler.h | 4 +-- .../currency_protocol_handler.inl | 27 +++++++++++++------ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index 88586857..1ef06777 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -117,34 +117,34 @@ namespace net_utils //some helpers - inline - std::string print_connection_context(const connection_context_base& ctx) + inline std::string print_connection_context(const connection_context_base& ctx) { std::stringstream ss; ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT"); return ss.str(); } - inline - void print_connection_context_short(const connection_context_base& ctx, std::stringstream& ss) + inline std::ostream &operator <<(std::ostream &o, const connection_context_base& ctx) { - ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT"); - } + o << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT"); + return o; + } - inline - std::string print_connection_context_short(const connection_context_base& ctx) + inline std::string print_connection_context_short(const connection_context_base& ctx) { std::stringstream ss; - print_connection_context_short(ctx, ss); + ss << ctx; return ss.str(); } - inline std::string print_connection_context_list(const std::list& contexts) + inline std::string print_connection_context_list(const std::list& contexts, const std::string& delim = std::string("\n")) { std::stringstream ss; for (auto& c : contexts) { - ss << epee::string_tools::get_ip_string_from_int32(c.m_remote_ip) << ":" << c.m_remote_port << (c.m_is_income ? " INC" : " OUT") << ENDL; + if (ss.tellp()) + ss << delim; + ss << c; } return ss.str(); } @@ -179,7 +179,7 @@ namespace net_utils #define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message) -} -} +} // namespace net_utils +} // namespace epee #endif //_NET_UTILS_BASE_H_ diff --git a/src/currency_protocol/currency_protocol_handler.h b/src/currency_protocol/currency_protocol_handler.h index 08dd8ea8..58f9d218 100644 --- a/src/currency_protocol/currency_protocol_handler.h +++ b/src/currency_protocol/currency_protocol_handler.h @@ -119,7 +119,7 @@ namespace currency template bool post_notify(typename t_parametr::request& arg, currency_connection_context& context) { - LOG_PRINT_L2("[POST]" << typeid(t_parametr).name()); + LOG_PRINT_L2("[POST]" << typeid(t_parametr).name() << " to " << context); std::string blob; epee::serialization::store_t_to_binary(arg, blob); return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context); @@ -133,7 +133,7 @@ namespace currency std::list relayed_peers; bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers); - LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " relayed contexts list: " << ENDL << print_connection_context_list(relayed_peers), LOG_LEVEL_2); + LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " relayed contexts list: " << print_connection_context_list(relayed_peers, ", "), LOG_LEVEL_2); return r; } }; diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index d9a36d8d..e9ca4eb7 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -94,22 +94,32 @@ namespace currency << std::setw(20) << "Peer id" << std::setw(25) << "Recv/Sent (idle,sec)" << std::setw(25) << "State" - << std::setw(20) << "Livetime(seconds)" + << std::setw(20) << "Livetime" << std::setw(20) << "Client version" << ENDL; + size_t incoming_count = 0, outgoing_count = 0; + std::multimap conn_map; m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id) { - ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") + + std::stringstream conn_ss; + time_t livetime = time(NULL) - cntxt.m_started; + conn_ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") + string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) << std::setw(20) << std::hex << peer_id << std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")" << std::setw(25) << get_protocol_state_string(cntxt.m_state) - << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started) + << std::setw(20) << epee::misc_utils::get_time_interval_string(livetime) << std::setw(20) << cntxt.m_remote_version << ENDL; + conn_map.insert(std::make_pair(livetime, conn_ss.str())); + (cntxt.m_is_income ? incoming_count : outgoing_count) += 1; return true; }); - LOG_PRINT_L0("Connections: " << ENDL << ss.str()); + + for(auto it = conn_map.rbegin(); it != conn_map.rend(); ++it) + ss << it->second; + + LOG_PRINT_L0("Connections (" << incoming_count << " in, " << outgoing_count << " out, " << incoming_count + outgoing_count << " total):" << ENDL << ss.str()); } //------------------------------------------------------------------------------------------------------------------------ template @@ -723,13 +733,14 @@ namespace currency if (req.txs.size()) { post_notify(req, cc); - print_connection_context_short(cc, debug_ss); - debug_ss << ": " << req.txs.size() << ENDL; + + if (debug_ss.tellp()) + debug_ss << ", "; + debug_ss << cc << ": " << req.txs.size(); } } TIME_MEASURE_FINISH_MS(ms); - LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms)contexts list: " << debug_ss.str(), LOG_LEVEL_2); - + LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms) to: " << debug_ss.str(), LOG_LEVEL_2); } //------------------------------------------------------------------------------------------------------------------------ template From b24f3b5d6c1213297e7a48c596aab92a66349cb8 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 23 Oct 2019 14:03:47 +0300 Subject: [PATCH 06/14] p2p: attempt to fix double connections between nodes (#135) --- src/p2p/net_node.h | 2 ++ src/p2p/net_node.inl | 45 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 2c0a840b..29ff8705 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -32,6 +32,7 @@ using namespace epee; #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "p2p" +ENABLE_CHANNEL_BY_DEFAULT(LOG_DEFAULT_CHANNEL); #define CURRENT_P2P_STORAGE_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+13) @@ -198,6 +199,7 @@ namespace nodetool bool make_new_connection_from_peerlist(bool use_white_list); bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, bool white = true); size_t get_random_index_with_fixed_probability(size_t max_index); + bool is_peer_id_used(const peerid_type id); bool is_peer_used(const peerlist_entry& peer); bool is_addr_connected(const net_address& peer); template diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index d81eaeea..ec03b250 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -511,6 +511,13 @@ namespace nodetool return; } + if (is_peer_id_used(rsp.node_data.peer_id)) + { + LOG_PRINT_L0("It seems that peer " << std::hex << rsp.node_data.peer_id << " has already been connected, dropping connection"); + hsh_result = false; + return; + } + pi = context.peer_id = rsp.node_data.peer_id; m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port); @@ -535,7 +542,7 @@ namespace nodetool if(!hsh_result) { - LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed"); + LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed, closing connection"); m_net_server.get_config_object().close(context_.m_connection_id); } @@ -597,6 +604,26 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + bool node_server::is_peer_id_used(const peerid_type id) + { + if (id == m_config.m_peer_id) + return true; // ourself + + bool used = false; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if (id == cntxt.peer_id) + { + used = true; + return false; // stop enumerating + } + return true; + }); + + return used; + } + //----------------------------------------------------------------------------------- + template bool node_server::is_peer_used(const peerlist_entry& peer) { @@ -638,7 +665,7 @@ namespace nodetool template bool node_server::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white) { - LOG_PRINT_L0("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")..."); + LOG_PRINT_L1("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")..."); typename net_server::t_connection_context con = AUTO_VAL_INIT(con); bool res = m_net_server.connect(string_tools::get_ip_string_from_int32(na.ip), @@ -647,7 +674,7 @@ namespace nodetool con); if(!res) { - LOG_PRINT_L0("Connect failed to " + LOG_PRINT_L1("Connect failed to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) /*<< ", try " << try_count*/); @@ -807,7 +834,10 @@ namespace nodetool if(is_addr_connected(na)) continue; - try_to_connect_and_handshake_with_new_peer(na); + if (!try_to_connect_and_handshake_with_new_peer(na)) + { + LOG_PRINT_L0("connection to priority node " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << " failed"); + } } if(m_use_only_priority_peers) return true; @@ -1310,6 +1340,13 @@ namespace nodetool return 1; } + if (is_peer_id_used(arg.node_data.peer_id)) + { + LOG_PRINT_CCONTEXT_L1("COMMAND_HANDSHAKE came, but seems that peer " << std::hex << arg.node_data.peer_id << " has already been connected to this node, dropping connection"); + drop_connection(context); + return 1; + } + if (!tools::check_remote_client_version(arg.payload_data.client_version)) { LOG_PRINT_CCONTEXT_L2("COMMAND_HANDSHAKE: wrong client version: " << arg.payload_data.client_version << ", closing connection."); From 309821c985583c4a2787f80dd852b9d0ffe97a20 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 23 Oct 2019 14:04:57 +0300 Subject: [PATCH 07/14] performance tests: free space check test improved (#133) --- tests/performance_tests/free_space_check.h | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/performance_tests/free_space_check.h b/tests/performance_tests/free_space_check.h index f7fb2d5c..9ab54e13 100644 --- a/tests/performance_tests/free_space_check.h +++ b/tests/performance_tests/free_space_check.h @@ -11,6 +11,8 @@ #include "misc_log_ex.h" +namespace fs = boost::filesystem; + std::string exec(const char* cmd) { std::array buffer; @@ -32,11 +34,59 @@ std::string exec(const char* cmd) return result; } +bool try_write_test_file(size_t size_bytes) +{ + + static const std::string filename = "test_out_file"; + static const fs::path filename_p = filename; + + try + { + fs::ofstream s; + s.open(filename, std::ios_base::binary | std::ios_base::out| std::ios::trunc); + if(s.fail()) + return false; + + uint8_t block[32 * 1024] = {}; + crypto::generate_random_bytes(sizeof block, &block); + size_t size_total = 0; + for (size_t i = 0; i < size_bytes / (sizeof block); ++i) + { + s.write((const char*)&block, sizeof block); + size_total += sizeof block; + } + + if (size_bytes > size_total) + s.write((const char*)&block, size_bytes - size_total); + + s.close(); + + size_t size_actual = fs::file_size(filename_p); + CHECK_AND_ASSERT_MES(size_bytes == size_actual, false, "size_bytes = " << size_bytes << ", size_actual = " << size_actual); + + CHECK_AND_ASSERT_MES(fs::remove(filename_p), false, "remove failed"); + } + catch (std::exception& e) + { + LOG_PRINT_RED("caught: " << e.what(), LOG_LEVEL_0); + return false; + } + catch (...) + { + LOG_PRINT_RED("caught unknown exception", LOG_LEVEL_0); + return false; + } + + return true; +} + void free_space_check() { + static const size_t test_file_size = 1024 * 1024; namespace fs = boost::filesystem; std::string output; + bool r = false; #ifdef WIN32 output = exec("dir"); @@ -46,6 +96,9 @@ void free_space_check() LOG_PRINT_L0("test command output:" << std::endl << output); + r = try_write_test_file(test_file_size); + LOG_PRINT_L0("test file write: " << (r ? "OK" : "fail")); + boost::filesystem::path current_path("."); size_t counter = 0; @@ -80,6 +133,12 @@ void free_space_check() si = fs::space(current_path); LOG_PRINT_YELLOW("2) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0); + if (!try_write_test_file(test_file_size)) + { + LOG_PRINT_YELLOW("try_write_test_file(" << test_file_size << ") failed", LOG_LEVEL_0); + } + + need_backspace = false; } catch (std::exception& e) From 998ab7cfa8f9f5602ffb6a8ab08eb09dd8c494ed Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 23 Oct 2019 14:07:00 +0300 Subject: [PATCH 08/14] p2p: immediately close outgoing connection if handshake fails (fixes a rare connectivity bug) --- src/p2p/net_node.inl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ec03b250..71d9706c 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -688,9 +688,11 @@ namespace nodetool LOG_PRINT_CC_L0(con, "Failed to HANDSHAKE with peer " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) - /*<< ", try " << try_count*/); + << ", closing connection"); + m_net_server.get_config_object().close(con.m_connection_id); return false; } + if(just_take_peerlist) { m_net_server.get_config_object().close(con.m_connection_id); From 4135740ffd02c1998053467345b933865afe10da Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Oct 2019 00:46:17 +0300 Subject: [PATCH 09/14] p2p: formatting and comments --- .../currency_protocol_handler.h | 36 +++++++++---------- .../currency_protocol_handler.inl | 12 +++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/currency_protocol/currency_protocol_handler.h b/src/currency_protocol/currency_protocol_handler.h index 58f9d218..5faa2efb 100644 --- a/src/currency_protocol/currency_protocol_handler.h +++ b/src/currency_protocol/currency_protocol_handler.h @@ -22,7 +22,7 @@ PUSH_VS_WARNINGS DISABLE_VS_WARNINGS(4355) -#define ASYNC_RELAY_MODE +#define ASYNC_RELAY_MODE // relay transactions asyncronously via m_relay_que namespace currency { @@ -117,25 +117,25 @@ namespace currency int64_t m_last_ntp2local_time_difference; template - bool post_notify(typename t_parametr::request& arg, currency_connection_context& context) - { - LOG_PRINT_L2("[POST]" << typeid(t_parametr).name() << " to " << context); - std::string blob; - epee::serialization::store_t_to_binary(arg, blob); - return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context); - } + bool post_notify(typename t_parametr::request& arg, currency_connection_context& context) + { + LOG_PRINT_L3("[POST]" << typeid(t_parametr).name() << " to " << context); + std::string blob; + epee::serialization::store_t_to_binary(arg, blob); + return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context); + } - template - bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context) - { - std::string arg_buff; - epee::serialization::store_t_to_binary(arg, arg_buff); - std::list relayed_peers; - bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers); + template + bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context) + { + std::string arg_buff; + epee::serialization::store_t_to_binary(arg, arg_buff); + std::list relayed_peers; + bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers); - LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " relayed contexts list: " << print_connection_context_list(relayed_peers, ", "), LOG_LEVEL_2); - return r; - } + LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " to (" << relayed_peers.size() << "): " << print_connection_context_list(relayed_peers, ", "), LOG_LEVEL_2); + return r; + } }; } diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index e9ca4eb7..7ff9a340 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -245,7 +245,6 @@ namespace currency if(context.m_state != currency_connection_context::state_normal) return 1; - //check if block already exists block b = AUTO_VAL_INIT(b); block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -255,6 +254,7 @@ namespace currency m_p2p->drop_connection(context); return 1; } + crypto::hash block_id = get_block_hash(b); LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK " << block_id << " HEIGHT " << get_block_height(b) << " (hop " << arg.hop << ")", LOG_LEVEL_2); @@ -324,11 +324,11 @@ namespace currency m_p2p->drop_connection(context); return 1; } - LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA: id: " << block_id - << ",bvc.m_added_to_main_chain " << bvc.m_added_to_main_chain - //<< ",prevalidate_result " << prevalidate_relayed - << ",bvc.added_to_altchain " << bvc.added_to_altchain - << ",bvc.m_marked_as_orphaned " << bvc.m_marked_as_orphaned, LOG_LEVEL_2); + LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA " << block_id + << " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain + //<< ", prevalidate_result=" << prevalidate_relayed + << ", bvc.added_to_altchain=" << bvc.added_to_altchain + << ", bvc.m_marked_as_orphaned=" << bvc.m_marked_as_orphaned, LOG_LEVEL_2); if (bvc.m_added_to_main_chain || (bvc.added_to_altchain && bvc.height_difference < 2)) { From acc6d1a53bd7f8013fcbcec8202861d273df8b17 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Oct 2019 08:12:28 +0300 Subject: [PATCH 10/14] finalized wallet integrity on store, closes #57 --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c92fb801..880c5fc9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2066,7 +2066,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor { LOG_PRINT_L0("(before storing: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")"); - check_for_free_space_and_throw_if_it_lacks(path_to_save); + // check_for_free_space_and_throw_if_it_lacks(path_to_save); temporary disabled, wallet saving implemented in two-stage scheme to avoid data loss due to lack of space std::string ascii_path_to_save = epee::string_encoding::convert_to_ansii(path_to_save); From 7c5202dcabfa5f43b871c824f8592c59872b8dd7 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Oct 2019 08:13:37 +0300 Subject: [PATCH 11/14] wallet: fixed a bug with removing a temp file when write fails --- src/wallet/wallet2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 880c5fc9..2bb7b9c9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2099,8 +2099,9 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor r = tools::portble_serialize_obj_to_stream(*this, data_file); if (!r) { + data_file.close(); boost::filesystem::remove(tmp_file_path); // remove tmp file if smth went wrong - WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "portble_serialize_obj_to_stream failed for wallet " << tmp_file_path.string()); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "IO error while storing wallet to " << tmp_file_path.string() << " (portble_serialize_obj_to_stream failed)"); } data_file.flush(); From b9335fefc8812f527e1751ac94a8b924639b96fc Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Oct 2019 09:40:02 +0300 Subject: [PATCH 12/14] wallet: an attempt to fix #47 --- src/wallet/wallet2.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2bb7b9c9..e8d9b357 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2242,6 +2242,9 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a for(auto& utx : m_unconfirmed_txs) { + if (utx.second.contract.size()) + continue; // skip unconfirmed contract tx + if (utx.second.is_income) { balance_total += utx.second.amount; From 706395e88efdbc2829222f1ecaeaf79aca853a20 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 28 Oct 2019 20:45:25 +0300 Subject: [PATCH 13/14] coretests: escrow_acceptance_and_balance test added to cover #47 case more carefully --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/escrow_wallet_tests.cpp | 197 +++++++++++++++++++++++ tests/core_tests/escrow_wallet_tests.h | 17 ++ 3 files changed, 215 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 230cf874..500bc1a1 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -731,6 +731,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(escrow_cancellation_acceptance_expiration); // GENERATE_AND_PLAY(escrow_proposal_acceptance_in_alt_chain); -- work in progress GENERATE_AND_PLAY(escrow_zero_amounts); + GENERATE_AND_PLAY(escrow_acceptance_and_balance); GENERATE_AND_PLAY(escrow_altchain_meta_test<0>); GENERATE_AND_PLAY(escrow_altchain_meta_test<1>); diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index 600339ae..9bbc919f 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -3095,3 +3095,200 @@ bool escrow_zero_amounts::c1(currency::core& c, size_t ev_index, const std::vect return true; } +//------------------------------------------------------------------------------ + +escrow_acceptance_and_balance::escrow_acceptance_and_balance() + : m_alice_bob_start_amount(0) + , m_alice_bob_start_chunk_amount(0) + , m_alice_fee_proposal(0) + , m_bob_fee_accept(0) + , m_bob_fee_release(0) +{ + REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_not_confirmed); + REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_confirmed); + REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_not_confirmed); + REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_confirmed); +} + +bool escrow_acceptance_and_balance::generate(std::vector& events) const +{ + m_accounts.resize(TOTAL_ACCS_COUNT); + account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); + account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); + account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + m_alice_bob_start_amount = MK_TEST_COINS(200); + uint64_t amount_chunks = 10; + m_alice_bob_start_chunk_amount = m_alice_bob_start_amount / 10; + + transaction tx_0 = AUTO_VAL_INIT(tx_0); + bool r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), alice_acc.get_public_address(), m_alice_bob_start_amount, 10, TESTS_DEFAULT_FEE, tx_0); + CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed"); + events.push_back(tx_0); + + transaction tx_1 = AUTO_VAL_INIT(tx_1); + r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), bob_acc.get_public_address(), m_alice_bob_start_amount, 10, TESTS_DEFAULT_FEE, tx_1); + CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed"); + events.push_back(tx_1); + + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list({tx_0, tx_1})); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + // prepare contract details + m_cpd = AUTO_VAL_INIT(m_cpd); + m_cpd.amount_a_pledge = MK_TEST_COINS(7); + m_cpd.amount_b_pledge = MK_TEST_COINS(5); + m_cpd.amount_to_pay = MK_TEST_COINS(3); + m_cpd.a_addr = alice_acc.get_public_address(); + m_cpd.b_addr = bob_acc.get_public_address(); + m_alice_fee_proposal = MK_TEST_COINS(4); + m_bob_fee_accept = MK_TEST_COINS(2); + m_bob_fee_release = MK_TEST_COINS(9); // Alice states that Bob should pay this much money for upcoming contract release (which will be sent by Alice) + + std::vector used_sources; + + // escrow proposal + bc_services::proposal_body prop = AUTO_VAL_INIT(prop); + transaction escrow_proposal_tx = AUTO_VAL_INIT(escrow_proposal_tx); + r = build_custom_escrow_proposal(events, blk_1r, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_1r.timestamp + 36000, 0, m_alice_fee_proposal, m_bob_fee_release, eccf_normal, escrow_proposal_tx, used_sources, &prop); + CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); + events.push_back(escrow_proposal_tx); + + DO_CALLBACK(events, "check_balance_after_proposal_not_confirmed"); + + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, escrow_proposal_tx); + + DO_CALLBACK(events, "check_balance_after_proposal_confirmed"); + + MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); + + DO_CALLBACK(events, "check_balance_after_proposal_confirmed"); + + // escrow proposal acceptance + transaction escrow_normal_acceptance_tx = prop.tx_template; + uint64_t normal_acceptance_mask = eccf_normal; + r = build_custom_escrow_accept_proposal(events, blk_2, 0, bob_acc.get_keys(), m_cpd, 0, 0, 0, 0, m_bob_fee_accept, m_bob_fee_release, normal_acceptance_mask, prop.tx_onetime_secret_key, escrow_normal_acceptance_tx, used_sources); + CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_accept_proposal failed"); + + events.push_back(escrow_normal_acceptance_tx); + + DO_CALLBACK(events, "check_balance_after_acceptance_not_confirmed"); + + MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, escrow_normal_acceptance_tx); + + DO_CALLBACK(events, "check_balance_after_acceptance_confirmed"); + + MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc); + + DO_CALLBACK(events, "check_balance_after_acceptance_confirmed"); + + return true; +} + +bool escrow_acceptance_and_balance::check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector& events) +{ + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, + m_alice_bob_start_amount - m_alice_fee_proposal, // total + true, UINT64_MAX, + m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + MK_TEST_COINS(0) // awainted out + ), false, ""); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, + m_alice_bob_start_amount, // total + true, UINT64_MAX, + m_alice_bob_start_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + MK_TEST_COINS(0) // awaited out + ), false, ""); + + return true; +} + +bool escrow_acceptance_and_balance::check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector& events) +{ + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, + m_alice_bob_start_amount - m_alice_fee_proposal, // total + true, UINT64_MAX, + m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + MK_TEST_COINS(0) // awaited out + ), false, ""); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, + m_alice_bob_start_amount, // total + true, UINT64_MAX, + m_alice_bob_start_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + MK_TEST_COINS(0) // awaited out + ), false, ""); + + return true; +} + +bool escrow_acceptance_and_balance::check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector& events) +{ + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, + m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total + true, UINT64_MAX, + m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + m_cpd.amount_a_pledge + m_cpd.amount_to_pay), // awaited out + false, ""); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, + m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total + true, UINT64_MAX, + m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + m_cpd.amount_b_pledge + m_bob_fee_release), // awaited out + false, ""); + + return true; +} + +bool escrow_acceptance_and_balance::check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector& events) +{ + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, + m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total + true, UINT64_MAX, + m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + MK_TEST_COINS(0) // awaited out + ), false, ""); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, + m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total + true, UINT64_MAX, + m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked + 0, // mined + MK_TEST_COINS(0), // awaited in + MK_TEST_COINS(0) // awaited out + ), false, ""); + + return true; +} diff --git a/tests/core_tests/escrow_wallet_tests.h b/tests/core_tests/escrow_wallet_tests.h index 33fdb457..332ac5a2 100644 --- a/tests/core_tests/escrow_wallet_tests.h +++ b/tests/core_tests/escrow_wallet_tests.h @@ -141,3 +141,20 @@ struct escrow_zero_amounts : public wallet_test bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct escrow_acceptance_and_balance : public wallet_test +{ + escrow_acceptance_and_balance(); + bool generate(std::vector& events) const; + bool check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector& events); + bool check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector& events); + bool check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector& events); + bool check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector& events); + + mutable uint64_t m_alice_bob_start_amount; + mutable uint64_t m_alice_bob_start_chunk_amount; + mutable uint64_t m_alice_fee_proposal; + mutable uint64_t m_bob_fee_release; + mutable uint64_t m_bob_fee_accept; + mutable bc_services::contract_private_details m_cpd; +}; From da782cdd73eab2879db345f1f58a5efc1311b1bb Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 28 Oct 2019 21:07:34 +0300 Subject: [PATCH 14/14] wallet: fix for #47 --- src/wallet/wallet2.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index e8d9b357..5ffc9d8b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2230,7 +2230,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a for(auto& td : m_transfers) { - if (td.is_spendable() || td.is_reserved_for_escrow()) + if (td.is_spendable() || (td.is_reserved_for_escrow() && !td.is_spent())) { balance_total += td.amount(); if (is_transfer_unlocked(td)) @@ -2242,9 +2242,6 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a for(auto& utx : m_unconfirmed_txs) { - if (utx.second.contract.size()) - continue; // skip unconfirmed contract tx - if (utx.second.is_income) { balance_total += utx.second.amount;