From ca601b8fc8f398718b326adeafd72fb934e26693 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Sun, 16 Oct 2022 14:47:34 +0200 Subject: [PATCH 01/15] enabled zarcanum_test_n_inputs_validation for multiassets branch --- tests/core_tests/chaingen_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 133234bc..129198f9 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1062,7 +1062,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(zarcanum_basic_test); GENERATE_AND_PLAY(multiassets_basic_test); - //GENERATE_AND_PLAY(zarcanum_test_n_inputs_validation); + GENERATE_AND_PLAY(zarcanum_test_n_inputs_validation); // GENERATE_AND_PLAY(gen_block_reward); // END OF TESTS */ From a493ace766c314fee17393c1fa095c34f7d37152 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 15 Nov 2022 21:54:55 +0100 Subject: [PATCH 02/15] added api for assets management in wallet(whitelist and custom set) --- src/currency_core/currency_basic.h | 14 +++++++++++++- src/rpc/core_rpc_server.cpp | 11 +++++++++++ src/rpc/core_rpc_server.h | 5 ++++- src/rpc/core_rpc_server_commands_defs.h | 23 +++++++++++++++++++++++ src/wallet/core_default_rpc_proxy.cpp | 5 +++++ src/wallet/core_default_rpc_proxy.h | 1 + src/wallet/core_fast_rpc_proxy.h | 5 +++++ src/wallet/wallet2.cpp | 25 +++++++++++++++++++++++++ src/wallet/wallet2.h | 6 ++++++ 9 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 9ab8a12f..abfc69ae 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -727,7 +727,6 @@ namespace currency }; - struct asset_descriptor_base { uint64_t total_max_supply = 0; @@ -735,6 +734,7 @@ namespace currency uint8_t decimal_point = 12; std::string ticker; std::string full_name; + std::string meta_info; crypto::public_key owner = currency::null_pkey; BEGIN_VERSIONED_SERIALIZE() @@ -743,6 +743,7 @@ namespace currency FIELD(decimal_point) FIELD(ticker) FIELD(full_name) + FIELD(meta_info) FIELD(owner) END_SERIALIZE() @@ -753,8 +754,19 @@ namespace currency BOOST_SERIALIZE(decimal_point) BOOST_SERIALIZE(ticker) BOOST_SERIALIZE(full_name) + BOOST_SERIALIZE(meta_info) BOOST_SERIALIZE(owner) END_BOOST_SERIALIZATION() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(total_max_supply) + KV_SERIALIZE(current_supply) + KV_SERIALIZE(decimal_point) + KV_SERIALIZE(ticker) + KV_SERIALIZE(full_name) + KV_SERIALIZE(meta_info) + KV_SERIALIZE_POD_AS_HEX_STRING(owner) + END_KV_SERIALIZE_MAP() }; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 948472c0..19a73be6 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -627,6 +627,17 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_asset_info(req.asset_id, res.asset_descriptor)) + { + res.status = API_RETURN_CODE_NOT_FOUND; + return true; + } + res.status = API_RETURN_CODE_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details)) diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index d27ceada..4e52d22d 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -82,7 +82,8 @@ namespace currency bool on_get_pool_txs_brief_details(const COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::request& req, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::response& res, connection_context& cntx); bool on_get_all_pool_tx_list(const COMMAND_RPC_GET_ALL_POOL_TX_LIST::request& req, COMMAND_RPC_GET_ALL_POOL_TX_LIST::response& res, connection_context& cntx); bool on_get_pool_info(const COMMAND_RPC_GET_POOL_INFO::request& req, COMMAND_RPC_GET_POOL_INFO::response& res, connection_context& cntx); - + bool on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx); + bool on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alt_blocks_details(const COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::response& res, connection_context& cntx); @@ -137,6 +138,8 @@ namespace currency MAP_JON_RPC ("get_pool_txs_brief_details", on_get_pool_txs_brief_details, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS) MAP_JON_RPC ("get_all_pool_tx_list", on_get_all_pool_tx_list, COMMAND_RPC_GET_ALL_POOL_TX_LIST) MAP_JON_RPC ("get_pool_info", on_get_pool_info, COMMAND_RPC_GET_POOL_INFO) + //assets api + MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO) MAP_JON_RPC_WE("get_main_block_details", on_get_main_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 4b737eba..8f2ae19e 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -82,6 +82,29 @@ namespace currency }; }; + struct COMMAND_RPC_GET_ASSET_INFO + { + struct request + { + crypto::hash asset_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + asset_descriptor_base asset_descriptor; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(asset_descriptor) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_GET_HEIGHT { struct request diff --git a/src/wallet/core_default_rpc_proxy.cpp b/src/wallet/core_default_rpc_proxy.cpp index 7e4a4ed6..3643313e 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -168,6 +168,11 @@ namespace tools return invoke_http_json_rpc_update_is_disconnect("get_pool_info", req, res); } //------------------------------------------------------------------------------------------------------------------------------ + bool default_http_core_proxy::call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) + { + return invoke_http_json_rpc_update_is_disconnect("get_asset_info", req, res); + } + //------------------------------------------------------------------------------------------------------------------------------ bool default_http_core_proxy::get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) { return tools::get_transfer_address(adr_str, addr, payment_id, this); diff --git a/src/wallet/core_default_rpc_proxy.h b/src/wallet/core_default_rpc_proxy.h index 89234151..70ec4ea4 100644 --- a/src/wallet/core_default_rpc_proxy.h +++ b/src/wallet/core_default_rpc_proxy.h @@ -51,6 +51,7 @@ namespace tools bool call_COMMAND_RPC_GET_BLOCKS_DETAILS(const currency::COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, currency::COMMAND_RPC_GET_BLOCKS_DETAILS::response& res) override; bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res) override; bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_POOL_INFO::request& req, currency::COMMAND_RPC_GET_POOL_INFO::response& res) override; + bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) override; bool check_connection() override; bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override; diff --git a/src/wallet/core_fast_rpc_proxy.h b/src/wallet/core_fast_rpc_proxy.h index 7e3478c9..3e3f9b40 100644 --- a/src/wallet/core_fast_rpc_proxy.h +++ b/src/wallet/core_fast_rpc_proxy.h @@ -133,6 +133,11 @@ namespace tools return m_rpc.on_get_pool_info(req, res, m_cntxt_stub); } //------------------------------------------------------------------------------------------------------------------------------ + virtual bool call_COMMAND_RPC_GET_ASSET_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res)override + { + return m_rpc.on_get_asset_info(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override { return tools::get_transfer_address(adr_str, addr, payment_id, this); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f51c6d7e..f727197e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3131,6 +3131,31 @@ uint64_t wallet2::balance() const return balance(stub, stub, stub, stub); } //---------------------------------------------------------------------------------------------------- +bool wallet2::add_custom_asset_id(const crypto::hash& asset_id) +{ + currency::COMMAND_RPC_GET_ASSET_INFO::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_ASSET_INFO::response resp = AUTO_VAL_INIT(resp); + + bool r = m_core_proxy->call_COMMAND_RPC_GET_ASSET_INFO(req, resp); + if (resp.status == API_RETURN_CODE_OK) + { + m_custom_assets[asset_id] = resp.asset_descriptor; + return true; + } + return false; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::delete_custom_asset_id(const crypto::hash& asset_id) +{ + auto it = m_custom_assets.find(asset_id); + if (it != m_custom_assets.end()) + { + m_custom_assets.erase(it); + } + + return true; +} +//---------------------------------------------------------------------------------------------------- void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) const { incoming_transfers = m_transfers; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 6d1d470a..c86f5b0e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -813,6 +813,7 @@ namespace tools return; a & m_own_asset_descriptors; + a & m_custom_assets; } void wipeout_extra_if_needed(std::vector& transfer_history); @@ -894,6 +895,8 @@ namespace tools void set_disable_tor_relay(bool disable); uint64_t get_default_fee() {return TX_DEFAULT_FEE;} void export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions = true); + + bool add_custom_asset_id(const crypto::hash& asset_id); /* create_htlc_proposal: if htlc_hash == null_hash, then this wallet is originator of the atomic process, and @@ -1091,6 +1094,9 @@ private: std::unordered_set m_unconfirmed_multisig_transfers; std::unordered_map m_tx_keys; std::unordered_map m_own_asset_descriptors; + std::unordered_map m_custom_assets; //assets that manually added by user + std::unordered_map m_whitelisted_assets; //assets that manually added by user + std::multimap m_htlcs; //map [expired_if_more_then] -> height of expiration amount_gindex_to_transfer_id_container m_active_htlcs; // map [amount; gindex] -> transfer index From e839761ae94733f7457738e56c356c44ac58f892 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 16 Nov 2022 22:16:15 +0100 Subject: [PATCH 03/15] implemented https support and tokens whitelisting(just inital declaration) --- contrib/epee/include/net/http_client.h | 216 +---- contrib/epee/include/net/net_helper.h | 1189 +++++++++++++----------- src/wallet/wallet2.cpp | 5 + src/wallet/wallet2.h | 4 +- 4 files changed, 667 insertions(+), 747 deletions(-) diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index c0b57596..515da64a 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -38,9 +38,9 @@ #include "net_helper.h" #include "http_client_base.h" -//#ifdef HTTP_ENABLE_GZIP +#ifdef HTTP_ENABLE_GZIP #include "gzip_encoding.h" -//#endif +#endif #include "string_tools.h" #include "reg_exp_definer.h" @@ -200,8 +200,8 @@ using namespace std; namespace http { - - class http_simple_client: public i_target_handler + template + class http_simple_client_t: public i_target_handler { public: @@ -227,14 +227,14 @@ using namespace std; }; - blocked_mode_client m_net_client; + blocked_mode_client_t m_net_client; std::string m_host_buff; std::string m_port; - //unsigned int m_timeout; - unsigned int m_connection_timeout; - unsigned int m_recv_timeout; + unsigned int m_timeout; std::string m_header_cache; http_response_info m_response_info; + size_t m_len_in_summary; + size_t m_len_in_remain; //std::string* m_ptarget_buffer; boost::shared_ptr m_pcontent_encoding_handler; reciev_machine_state m_state; @@ -242,10 +242,6 @@ using namespace std; std::string m_chunked_cache; critical_section m_lock; - protected: - uint64_t m_len_in_summary; - uint64_t m_len_in_remain; - public: void set_host_name(const std::string& name) { @@ -253,37 +249,24 @@ using namespace std; m_host_buff = name; } - boost::asio::ip::tcp::socket& get_socket() - { - return m_net_client.get_socket(); - } + //boost::asio::ip::tcp::socket& get_socket() + //{ + // return m_net_client.get_socket(); + //} bool connect(const std::string& host, int port, unsigned int timeout) { return connect(host, std::to_string(port), timeout); } - - bool set_timeouts(unsigned int connection_timeout, unsigned int recv_timeout) - { - m_connection_timeout = connection_timeout; - m_recv_timeout = recv_timeout; - return true; - } - - bool connect(const std::string& host, std::string port) + bool connect(const std::string& host, const std::string& port, unsigned int timeout) { CRITICAL_REGION_LOCAL(m_lock); m_host_buff = host; m_port = port; + m_timeout = timeout; - return m_net_client.connect(host, port, m_connection_timeout, m_recv_timeout); - } - - bool connect(const std::string& host, const std::string& port, unsigned int timeout) - { - m_connection_timeout = m_recv_timeout = timeout; - return connect(host, port); + return m_net_client.connect(host, port, timeout, timeout); } //--------------------------------------------------------------------------- bool disconnect() @@ -320,7 +303,7 @@ using namespace std; if(!is_connected()) { LOG_PRINT("Reconnecting...", LOG_LEVEL_3); - if(!connect(m_host_buff, m_port)) + if(!connect(m_host_buff, m_port, m_timeout)) { LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3); return false; @@ -464,14 +447,7 @@ using namespace std; } CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); m_len_in_remain -= recv_buff.size(); - bool r = m_pcontent_encoding_handler->update_in(recv_buff); - //CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_pcontent_encoding_handler->update_in returned false"); - if (!r) - { - m_state = reciev_machine_state_error; - disconnect(); - return false; - } + m_pcontent_encoding_handler->update_in(recv_buff); if(m_len_in_remain == 0) m_state = reciev_machine_state_done; @@ -507,7 +483,7 @@ using namespace std; } //--------------------------------------------------------------------------- inline - bool get_len_from_chunk_head(const std::string &chunk_head, uint64_t& result_size) + bool get_len_from_chunk_head(const std::string &chunk_head, size_t& result_size) { std::stringstream str_stream; str_stream << std::hex; @@ -518,7 +494,7 @@ using namespace std; } //--------------------------------------------------------------------------- inline - bool get_chunk_head(std::string& buff, uint64_t& chunk_size, bool& is_matched) + bool get_chunk_head(std::string& buff, size_t& chunk_size, bool& is_matched) { is_matched = false; size_t offset = 0; @@ -831,7 +807,7 @@ using namespace std; return false; }else { //Apparently there are no signs of the form of transfer, will receive data until the connection is closed - m_state = reciev_machine_state_body_connection_close; + m_state = reciev_machine_state_error; LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache, LOG_LEVEL_2); return false; } @@ -874,13 +850,14 @@ using namespace std; return true; } }; - // class http_simple_client - + typedef http_simple_client_t http_simple_client; + typedef http_simple_client_t https_simple_client; /************************************************************************/ /* */ /************************************************************************/ + //inline template bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) { @@ -894,150 +871,13 @@ using namespace std; if(!u_c.port) u_c.port = 80;//default for http - if (!tr.connect(u_c.host, static_cast(u_c.port), timeout)) - { - LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); - return false; - } + res = tr.connect(u_c.host, static_cast(u_c.port), timeout); + CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port); } return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); } - struct idle_handler_base - { - virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) = 0; - virtual ~idle_handler_base() {} - }; - - template - struct idle_handler : public idle_handler_base - { - callback_t m_cb; - - idle_handler(callback_t cb) : m_cb(cb) {} - virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) - { - return m_cb(piece_of_data, total_bytes, received_bytes); - } - }; - - class interruptible_http_client : public http_simple_client - { - std::shared_ptr m_pcb; - bool m_permanent_error = false; - - virtual bool handle_target_data(std::string& piece_of_transfer) - { - bool r = m_pcb->do_call(piece_of_transfer, m_len_in_summary, m_len_in_summary - m_len_in_remain); - piece_of_transfer.clear(); - return r; - } - - public: - template - bool invoke_cb(callback_t cb, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) - { - m_pcb.reset(new idle_handler(cb)); - const http_response_info* p_hri = nullptr; - bool r = invoke_request(url, *this, timeout, &p_hri, method, body, additional_params); - if (p_hri && !(p_hri->m_response_code >= 200 && p_hri->m_response_code < 300)) - { - LOG_PRINT_L0("HTTP request to " << url << " failed with code: " << p_hri->m_response_code); - m_permanent_error = true; - return false; - } - return r; - } - - template - bool download(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) - { - std::ofstream fs; - fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); - if (!fs.is_open()) - { - LOG_ERROR("Fsiled to open " << path_for_file); - return false; - } - auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) - { - fs.write(piece_of_data.data(), piece_of_data.size()); - return cb(total_bytes, received_bytes); - }; - bool r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params); - fs.close(); - return r; - } - - // - template - bool download_and_unzip(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), uint64_t fails_count = 1000, const fields_list& additional_params = fields_list()) - { - std::ofstream fs; - fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); - if (!fs.is_open()) - { - LOG_ERROR("Fsiled to open " << path_for_file); - return false; - } - std::string buff; - gzip_decoder_lambda zip_decoder; - uint64_t state_total_bytes = 0; - uint64_t state_received_bytes_base = 0; - uint64_t state_received_bytes_current = 0; - bool stopped = false; - auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) - { - //remember total_bytes only for first attempt, where fetched full lenght of the file - if (!state_total_bytes) - state_total_bytes = total_bytes; - - buff += piece_of_data; - return zip_decoder.update_in(buff, [&](const std::string& unpacked_buff) - { - state_received_bytes_current = received_bytes; - fs.write(unpacked_buff.data(), unpacked_buff.size()); - stopped = !cb(unpacked_buff, state_total_bytes, state_received_bytes_base + received_bytes); - return !stopped; - }); - }; - uint64_t current_err_count = 0; - bool r = false; - m_permanent_error = false; - while (!r && current_err_count < fails_count) - { - LOG_PRINT_L0("Attempt " << current_err_count + 1 << "/" << fails_count << " to get " << url << " (offset:" << state_received_bytes_base << ")"); - fields_list additional_params_local = additional_params; - additional_params_local.push_back(std::make_pair("Range", std::string("bytes=") + std::to_string(state_received_bytes_base) + "-")); - r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params_local); - if (!r) - { - if (stopped || m_permanent_error) - break; - current_err_count++; - state_received_bytes_base += state_received_bytes_current; - state_received_bytes_current = 0; - boost::this_thread::sleep_for(boost::chrono::milliseconds(2000)); - } - } - - if (current_err_count >= fails_count) - { - LOG_PRINT_YELLOW("Downloading from " << url << " FAILED as it's reached maximum (" << fails_count << ") number of attempts. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); - } - else if (m_permanent_error) - { - LOG_PRINT_YELLOW("Downloading from " << url << " FAILED due to permanent HTTP error. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); - } - - fs.close(); - return r; - } - }; - - - } // namespace http - -} // namespace net_utils -} // namespace epee + } +} +} diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 72ff4e75..8f391994 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -38,12 +38,14 @@ #include #include #include +#include #include #include #include #include #include "net/net_utils_base.h" #include "misc_language.h" +#include "misc_helpers.h" //#include "profile_tools.h" #include "../string_tools.h" @@ -54,637 +56,708 @@ namespace epee { -namespace net_utils -{ + namespace net_utils + { - class blocked_mode_client - { - - - struct handler_obj - { - handler_obj(boost::system::error_code& error, size_t& bytes_transferred):ref_error(error), ref_bytes_transferred(bytes_transferred) - {} - handler_obj(const handler_obj& other_obj):ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred) - {} - - boost::system::error_code& ref_error; - size_t& ref_bytes_transferred; - - void operator()(const boost::system::error_code& error, // Result of operation. - std::size_t bytes_transferred // Number of bytes read. - ) - { - ref_error = error; - ref_bytes_transferred = bytes_transferred; - } - }; - - public: - inline - blocked_mode_client():m_socket(m_io_service), - m_initialized(false), - m_connected(false), - m_deadline(m_io_service), - m_shutdowned(0), - m_connect_timeout{}, - m_reciev_timeout{} - { - - - m_initialized = true; + template + struct socket_backend; - // No deadline is required until the first socket operation is started. We - // set the deadline to positive infinity so that the actor takes no action - // until a specific deadline is set. - m_deadline.expires_at(boost::posix_time::pos_infin); - - // Start the persistent actor that checks for deadline expiry. - check_deadline(); - - } - inline - ~blocked_mode_client() - { - NESTED_TRY_ENTRY(); - - //profile_tools::local_coast lc("~blocked_mode_client()", 3); - shutdown(); - - NESTED_CATCH_ENTRY(__func__); - } - - inline void set_recv_timeout(int reciev_timeout) - { - m_reciev_timeout = reciev_timeout; - } - - inline - bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + template<> + struct socket_backend { - return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip); - } + socket_backend(boost::asio::io_service& _io_service): m_ssl_context(boost::asio::ssl::context::sslv23), m_socket(_io_service, m_ssl_context) + { + // Create a context that uses the default paths for + // finding CA certificates. + m_ssl_context.set_default_verify_paths(); + } - inline - bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") - { - m_connect_timeout = connect_timeout; - m_reciev_timeout = reciev_timeout; - m_connected = false; - if(!m_reciev_timeout) - m_reciev_timeout = m_connect_timeout; + boost::asio::ip::tcp::socket& get_socket() + { + return m_socket.next_layer(); + } - try - { - m_socket.close(); - // Get a list of endpoints corresponding to the server name. - + auto& get_stream() + { + return m_socket; + } - ////////////////////////////////////////////////////////////////////////// + void on_after_connect() + { + m_socket.handshake(boost::asio::ssl::stream_base::client); + } - boost::asio::ip::tcp::resolver resolver(m_io_service); - boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port); - boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); - boost::asio::ip::tcp::resolver::iterator end; - if(iterator == end) - { - LOG_ERROR("Failed to resolve " << addr); - return false; - } + private: + boost::asio::ssl::context m_ssl_context; + boost::asio::ssl::stream m_socket; + }; - ////////////////////////////////////////////////////////////////////////// + template<> + struct socket_backend + { + socket_backend(boost::asio::io_service& _io_service): m_socket(_io_service) + {} + + boost::asio::ip::tcp::socket& get_socket() + { + return m_socket; + } + + boost::asio::ip::tcp::socket& get_stream() + { + return m_socket; + } + + void on_after_connect() + { + + } + private: + boost::asio::ip::tcp::socket m_socket; + }; - //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); - boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); - m_socket.open(remote_endpoint.protocol()); - if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) - { - boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); - m_socket.bind(local_endpoint); - } + template + class blocked_mode_client_t + { + struct handler_obj + { + handler_obj(boost::system::error_code& error, size_t& bytes_transferred) :ref_error(error), ref_bytes_transferred(bytes_transferred) + {} + handler_obj(const handler_obj& other_obj) :ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred) + {} - - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout)); + boost::system::error_code& ref_error; + size_t& ref_bytes_transferred; + + void operator()(const boost::system::error_code& error, // Result of operation. + std::size_t bytes_transferred // Number of bytes read. + ) + { + ref_error = error; + ref_bytes_transferred = bytes_transferred; + } + }; + + public: + inline + blocked_mode_client_t() :m_sct_back(m_io_service), + m_initialized(false), + m_connected(false), + m_deadline(m_io_service), + m_shutdowned(0), + m_connect_timeout{}, + m_reciev_timeout{} + { - boost::system::error_code ec = boost::asio::error::would_block; - - //m_socket.connect(remote_endpoint); - m_socket.async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } - - if (!ec && m_socket.is_open()) - { - m_connected = true; - m_deadline.expires_at(boost::posix_time::pos_infin); - return true; - }else - { - LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3); - return false; - } - - } - catch(const boost::system::system_error& er) - { - LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4); - return false; - } - catch(...) - { - LOG_PRINT("Some fatal problems.", LOG_LEVEL_4); - return false; - } - - return true; - } + m_initialized = true; - inline - bool disconnect() - { - try - { - if(m_connected) - { - m_connected = false; - m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both); - - } - } - - catch(const boost::system::system_error& /*er*/) - { - //LOG_ERROR("Some problems at disconnect, message: " << er.what()); - return false; - } - catch(...) - { - //LOG_ERROR("Some fatal problems."); - return false; - } - return true; - } + // No deadline is required until the first socket operation is started. We + // set the deadline to positive infinity so that the actor takes no action + // until a specific deadline is set. + m_deadline.expires_at(boost::posix_time::pos_infin); + + // Start the persistent actor that checks for deadline expiry. + check_deadline(); + + } + inline + ~blocked_mode_client_t() + { + NESTED_TRY_ENTRY(); + + //profile_tools::local_coast lc("~blocked_mode_client()", 3); + shutdown(); + + NESTED_CATCH_ENTRY(__func__); + } + + inline void set_recv_timeout(int reciev_timeout) + { + m_reciev_timeout = reciev_timeout; + } + + inline + bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + { + return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip); + } + + inline + bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + { + m_connect_timeout = connect_timeout; + m_reciev_timeout = reciev_timeout; + m_connected = false; + if (!m_reciev_timeout) + m_reciev_timeout = m_connect_timeout; + + try + { + m_sct_back.get_socket().close(); + // Get a list of endpoints corresponding to the server name. - inline - bool send(const std::string& buff) - { + ////////////////////////////////////////////////////////////////////////// - try - { - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + boost::asio::ip::tcp::resolver resolver(m_io_service); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + boost::asio::ip::tcp::resolver::iterator end; + if (iterator == end) + { + LOG_ERROR("Failed to resolve " << addr); + return false; + } - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; + ////////////////////////////////////////////////////////////////////////// - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1); - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } + //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); + boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); - if (ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); + + m_sct_back.get_socket().open(remote_endpoint.protocol()); + if (bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "") + { + boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); + m_sct_back.get_socket().bind(local_endpoint); + } + + + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout)); + + + boost::system::error_code ec = boost::asio::error::would_block; + + //m_sct_back.get_socket().connect(remote_endpoint); + m_sct_back.get_socket().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (!ec && m_sct_back.get_socket().is_open()) + { + m_sct_back.on_after_connect(); + m_connected = true; + m_deadline.expires_at(boost::posix_time::pos_infin); + return true; + } + else + { + LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3); + return false; + } + + } + catch (const boost::system::system_error& er) + { + LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4); + return false; + } + catch (...) + { + LOG_PRINT("Some fatal problems.", LOG_LEVEL_4); + return false; + } + + return true; + } + + + inline + bool disconnect() + { + try + { + if (m_connected) + { + m_connected = false; + m_sct_back.get_socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both); + + } + } + + catch (const boost::system::system_error& /*er*/) + { + //LOG_ERROR("Some problems at disconnect, message: " << er.what()); + return false; + } + catch (...) + { + //LOG_ERROR("Some fatal problems."); + return false; + } + return true; + } + + + inline + bool send(const std::string& buff) + { + + try + { + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_sct_back.get_stream(), boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + m_connected = false; + return false; + } + else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at connect, message: " << er.what()); + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } + + inline + bool send(const void* data, size_t sz) + { + try + { + /* + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_sct_back.get_socket(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + */ + boost::system::error_code ec; + + size_t writen = m_sct_back.get_stream().write_some(boost::asio::buffer(data, sz), ec); + + + + if (!writen || ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + m_connected = false; + return false; + } + else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at send, message: " << er.what()); m_connected = false; - return false; - }else - { - m_deadline.expires_at(boost::posix_time::pos_infin); - } - } + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems."); + return false; + } - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at connect, message: " << er.what()); - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } + return true; + } - return true; - } + bool is_connected() + { + return m_connected && m_sct_back.get_socket().is_open(); + //TRY_ENTRY() + //return m_socket.is_open(); + //CATCH_ENTRY_L0("is_connected", false) + } - inline - bool send(const void* data, size_t sz) - { - try - { - /* - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + inline + bool recv(std::string& buff) + { - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; + try + { + // Set a deadline for the asynchronous operation. Since this function uses + // a composed operation (async_read_until), the deadline applies to the + // entire operation, rather than individual reads from the socket. + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + //boost::system::error_code ec = boost::asio::error::would_block; - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } - */ - boost::system::error_code ec; + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. - size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec); - + boost::system::error_code ec = boost::asio::error::would_block; + size_t bytes_transfered = 0; + + handler_obj hndlr(ec, bytes_transfered); + + char local_buff[10000] = { 0 }; + //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr); + boost::asio::async_read(m_sct_back.get_stream(), boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) + { + m_io_service.run_one(); + } - if (!writen || ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); + if (ec) + { + LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value()); + if (ec == boost::asio::error::eof) + { + LOG_PRINT_L4("Connection err_code eof."); + //connection closed there, empty + return true; + } + + LOG_PRINT_L3("Problems at read: " << ec.message()); + m_connected = false; + return false; + } + else + { + LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered); + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + /*if(!bytes_transfered) + return false;*/ + + buff.assign(local_buff, bytes_transfered); + return true; + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at read, message: " << er.what()); m_connected = false; - return false; - }else - { - m_deadline.expires_at(boost::posix_time::pos_infin); - } - } - - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at send, message: " << er.what()); - m_connected = false; - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } - - return true; - } - - bool is_connected() - { - return m_connected && m_socket.is_open(); - //TRY_ENTRY() - //return m_socket.is_open(); - //CATCH_ENTRY_L0("is_connected", false) - } - - inline - bool recv(std::string& buff) - { - - try - { - // Set a deadline for the asynchronous operation. Since this function uses - // a composed operation (async_read_until), the deadline applies to the - // entire operation, rather than individual reads from the socket. - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - //boost::system::error_code ec = boost::asio::error::would_block; - - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - - boost::system::error_code ec = boost::asio::error::would_block; - size_t bytes_transfered = 0; - - handler_obj hndlr(ec, bytes_transfered); - - char local_buff[10000] = {0}; - //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr); - boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr); - - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) - { - m_io_service.run_one(); - } - - - if (ec) - { - LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value()); - if(ec == boost::asio::error::eof) - { - LOG_PRINT_L4("Connection err_code eof."); - //connection closed there, empty - return true; - } - - LOG_PRINT_L3("Problems at read: " << ec.message()); - m_connected = false; - return false; - }else - { - LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered); - m_deadline.expires_at(boost::posix_time::pos_infin); - } - - /*if(!bytes_transfered) - return false;*/ - - buff.assign(local_buff, bytes_transfered); - return true; - } - - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at read, message: " << er.what()); - m_connected = false; - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems at read."); - return false; - } + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems at read."); + return false; + } - return false; + return false; - } + } - inline bool recv_n(std::string& buff, int64_t sz) - { + inline bool recv_n(std::string& buff, int64_t sz) + { - try - { - // Set a deadline for the asynchronous operation. Since this function uses - // a composed operation (async_read_until), the deadline applies to the - // entire operation, rather than individual reads from the socket. - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + try + { + // Set a deadline for the asynchronous operation. Since this function uses + // a composed operation (async_read_until), the deadline applies to the + // entire operation, rather than individual reads from the socket. + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - //boost::system::error_code ec = boost::asio::error::would_block; + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + //boost::system::error_code ec = boost::asio::error::would_block; - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. - buff.resize(static_cast(sz)); - boost::system::error_code ec = boost::asio::error::would_block; - size_t bytes_transfered = 0; + buff.resize(static_cast(sz)); + boost::system::error_code ec = boost::asio::error::would_block; + size_t bytes_transfered = 0; - - handler_obj hndlr(ec, bytes_transfered); - //char local_buff[10000] = {0}; - boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr); + handler_obj hndlr(ec, bytes_transfered); - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) - { - m_io_service.run_one(); - } + //char local_buff[10000] = {0}; + boost::asio::async_read(m_sct_back.get_stream(), boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr); - if (ec) - { - LOG_PRINT_L3("Problems at read: " << ec.message()); + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) + { + m_io_service.run_one(); + } + + if (ec) + { + LOG_PRINT_L3("Problems at read: " << ec.message()); + m_connected = false; + return false; + } + else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + if (bytes_transfered != buff.size()) + { + LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size()); + return false; + } + + return true; + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at read, message: " << er.what()); m_connected = false; - return false; - }else - { - m_deadline.expires_at(boost::posix_time::pos_infin); - } + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems at read."); + return false; + } - if(bytes_transfered != buff.size()) - { - LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size()); - return false; - } - return true; - } - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at read, message: " << er.what()); + return false; + } + + bool shutdown() + { + m_deadline.cancel(); + boost::system::error_code ignored_ec; + m_sct_back.get_socket().cancel(ignored_ec); + m_sct_back.get_socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_sct_back.get_socket().close(ignored_ec); + boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1); m_connected = false; - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems at read."); - return false; - } + return true; + } + + void set_connected(bool connected) + { + m_connected = connected; + } + boost::asio::io_service& get_io_service() + { + return m_io_service; + } + + boost::asio::ip::tcp::socket& get_socket() + { + return m_sct_back.get_socket(); + } + + private: + + void check_deadline() + { + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. This allows the blocked + // connect(), read_line() or write_line() functions to return. + LOG_PRINT_L3("Timed out socket"); + m_connected = false; + m_sct_back.get_socket().close(); + + // There is no longer an active deadline. The expiry is set to positive + // infinity so that the actor takes no action until a new deadline is set. + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + // Put the actor back to sleep. + m_deadline.async_wait(boost::bind(&blocked_mode_client_t::check_deadline, this)); + } - return false; - } - - bool shutdown() - { - m_deadline.cancel(); - boost::system::error_code ignored_ec; - m_socket.cancel(ignored_ec); - m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - m_socket.close(ignored_ec); - boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1); - m_connected = false; - return true; - } - - void set_connected(bool connected) - { - m_connected = connected; - } - boost::asio::io_service& get_io_service() - { - return m_io_service; - } - - boost::asio::ip::tcp::socket& get_socket() - { - return m_socket; - } - - private: - - void check_deadline() - { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) - { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - LOG_PRINT_L3("Timed out socket"); - m_connected = false; - m_socket.close(); - - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - m_deadline.expires_at(boost::posix_time::pos_infin); - } - - // Put the actor back to sleep. - m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this)); - } - - - - protected: - boost::asio::io_service m_io_service; - boost::asio::ip::tcp::socket m_socket; - int m_connect_timeout; - int m_reciev_timeout; - bool m_initialized; - bool m_connected; - boost::asio::deadline_timer m_deadline; - volatile uint32_t m_shutdowned; - }; + protected: + boost::asio::io_service m_io_service; + socket_backend m_sct_back; + int m_connect_timeout; + int m_reciev_timeout; + bool m_initialized; + bool m_connected; + boost::asio::deadline_timer m_deadline; + volatile uint32_t m_shutdowned; + }; - /************************************************************************/ - /* */ - /************************************************************************/ - class async_blocked_mode_client: public blocked_mode_client - { - public: - async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service) - { + /************************************************************************/ + /* */ + /************************************************************************/ + template + class async_blocked_mode_client_t : public blocked_mode_client_t + { + public: + async_blocked_mode_client_t() :m_send_deadline(blocked_mode_client::m_io_service) + { - // No deadline is required until the first socket operation is started. We - // set the deadline to positive infinity so that the actor takes no action - // until a specific deadline is set. - m_send_deadline.expires_at(boost::posix_time::pos_infin); + // No deadline is required until the first socket operation is started. We + // set the deadline to positive infinity so that the actor takes no action + // until a specific deadline is set. + m_send_deadline.expires_at(boost::posix_time::pos_infin); - // Start the persistent actor that checks for deadline expiry. - check_send_deadline(); - } - ~async_blocked_mode_client() - { - m_send_deadline.cancel(); - } - - bool shutdown() - { - blocked_mode_client::shutdown(); - m_send_deadline.cancel(); - return true; - } + // Start the persistent actor that checks for deadline expiry. + check_send_deadline(); + } + ~async_blocked_mode_client_t() + { + m_send_deadline.cancel(); + } - inline - bool send(const void* data, size_t sz) - { - try - { - /* - m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + bool shutdown() + { + blocked_mode_client::shutdown(); + m_send_deadline.cancel(); + return true; + } - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; + inline + bool send(const void* data, size_t sz) + { + try + { + /* + m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; - // Block until the asynchronous operation has completed. - while(ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - }*/ - - boost::system::error_code ec; + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); - size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec); + // Block until the asynchronous operation has completed. + while(ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + }*/ - if (!writen || ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); - return false; - }else - { - m_send_deadline.expires_at(boost::posix_time::pos_infin); - } - } + boost::system::error_code ec; - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at connect, message: " << er.what()); - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } + size_t writen = m_sct_back.get_socket().write_some(boost::asio::buffer(data, sz), ec); - return true; - } + if (!writen || ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + return false; + } + else + { + m_send_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at connect, message: " << er.what()); + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } - private: + private: - boost::asio::deadline_timer m_send_deadline; + boost::asio::deadline_timer m_send_deadline; - void check_send_deadline() - { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) - { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - LOG_PRINT_L3("Timed out socket"); - m_socket.close(); + void check_send_deadline() + { + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. This allows the blocked + // connect(), read_line() or write_line() functions to return. + LOG_PRINT_L3("Timed out socket"); + m_sct_back.get_socket().close(); - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - m_send_deadline.expires_at(boost::posix_time::pos_infin); - } + // There is no longer an active deadline. The expiry is set to positive + // infinity so that the actor takes no action until a new deadline is set. + m_send_deadline.expires_at(boost::posix_time::pos_infin); + } - // Put the actor back to sleep. - m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); - } - }; -} + // Put the actor back to sleep. + m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); + } + }; + + typedef blocked_mode_client_t blocked_mode_client; + typedef async_blocked_mode_client_t async_blocked_mode_client; + } } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f727197e..2e717df9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3154,6 +3154,11 @@ bool wallet2::delete_custom_asset_id(const crypto::hash& asset_id) } return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::load_whitelisted_tokens_list() +{ + } //---------------------------------------------------------------------------------------------------- void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) const diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c86f5b0e..d43650e6 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -897,7 +897,9 @@ namespace tools void export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions = true); bool add_custom_asset_id(const crypto::hash& asset_id); - + bool delete_custom_asset_id(const crypto::hash& asset_id); + bool load_whitelisted_tokens_list(); + /* create_htlc_proposal: if htlc_hash == null_hash, then this wallet is originator of the atomic process, and we use deterministic origin, if given some particular htlc_hash, then we use this hash, and this means that From ee6f8cf9720f8690f16e89c653eb0359a25ca74f Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 16 Nov 2022 22:27:49 +0100 Subject: [PATCH 04/15] right version of http_client.h --- contrib/epee/include/net/http_client.h | 1671 +++++++++++++----------- 1 file changed, 923 insertions(+), 748 deletions(-) diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 515da64a..76d823b9 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -38,9 +38,9 @@ #include "net_helper.h" #include "http_client_base.h" -#ifdef HTTP_ENABLE_GZIP +//#ifdef HTTP_ENABLE_GZIP #include "gzip_encoding.h" -#endif +//#endif #include "string_tools.h" #include "reg_exp_definer.h" @@ -57,827 +57,1002 @@ extern epee::critical_section gregexp_lock; namespace epee { -namespace net_utils -{ - -using namespace std; - - /*struct url - { - public: - void parse(const std::string& url_s) - { - const string prot_end("://"); - string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); - protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - ptr_fun(tolower)); // protocol is icase - if( prot_i == url_s.end() ) - return; - advance(prot_i, prot_end.length()); - string::const_iterator path_i = find(prot_i, url_s.end(), '/'); - host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - ptr_fun(tolower)); // host is icase - string::const_iterator query_i = find(path_i, url_s.end(), '?'); - path_.assign(path_i, query_i); - if( query_i != url_s.end() ) - ++query_i; - query_.assign(query_i, url_s.end()); - } - - std::string protocol_; - std::string host_; - std::string path_; - std::string query_; - };*/ - - - - - //--------------------------------------------------------------------------- - static inline const char* get_hex_vals() - { - static char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; - return hexVals; - } - - static inline const char* get_unsave_chars() - { - //static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&"; - static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&"; - return unsave_chars; - } - - static inline bool is_unsafe(unsigned char compare_char) - { - if(compare_char <= 32 || compare_char >= 123) - return true; - - const char* punsave = get_unsave_chars(); - - for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++) - if(compare_char == punsave[ichar_pos]) - return true; - - return false; - } - - static inline - std::string dec_to_hex(char num, int radix) - { - int temp=0; - std::string csTmp; - int num_char; - - num_char = (int) num; - if (num_char < 0) - num_char = 256 + num_char; - - while (num_char >= radix) - { - temp = num_char % radix; - num_char = (int)floor((float)num_char / (float)radix); - csTmp = get_hex_vals()[temp]; - } - - csTmp += get_hex_vals()[num_char]; - - if(csTmp.size() < 2) - { - csTmp += '0'; - } - - std::reverse(csTmp.begin(), csTmp.end()); - //_mbsrev((unsigned char*)csTmp.data()); - - return csTmp; - } - - static inline std::string convert(char val) - { - std::string csRet; - csRet += "%"; - csRet += dec_to_hex(val, 16); - return csRet; - } - static inline std::string conver_to_url_format(const std::string& uri) - { - - std::string result; - - for(size_t i = 0; i!= uri.size(); i++) - { - if(is_unsafe(uri[i])) - result += convert(uri[i]); - else - result += uri[i]; - - } - - return result; - } - - static inline std::string convert_to_url_format_force_all(const std::string& uri) + namespace net_utils { - std::string result; + using namespace std; - for(size_t i = 0; i!= uri.size(); i++) + /*struct url { - result += convert(uri[i]); + public: + void parse(const std::string& url_s) + { + const string prot_end("://"); + string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + ptr_fun(tolower)); // host is icase + string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); } - return result; - } + std::string protocol_; + std::string host_; + std::string path_; + std::string query_; + };*/ + //--------------------------------------------------------------------------- + static inline const char* get_hex_vals() + { + static char hexVals[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + return hexVals; + } - namespace http - { - template - class http_simple_client_t: public i_target_handler - { - public: - + static inline const char* get_unsave_chars() + { + //static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&"; + static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&"; + return unsave_chars; + } - private: - enum reciev_machine_state - { - reciev_machine_state_header, - reciev_machine_state_body_content_len, - reciev_machine_state_body_connection_close, - reciev_machine_state_body_chunked, - reciev_machine_state_done, - reciev_machine_state_error - }; + static inline bool is_unsafe(unsigned char compare_char) + { + if (compare_char <= 32 || compare_char >= 123) + return true; + const char* punsave = get_unsave_chars(); + for (int ichar_pos = 0; 0 != punsave[ichar_pos]; ichar_pos++) + if (compare_char == punsave[ichar_pos]) + return true; - enum chunked_state{ - http_chunked_state_chunk_head, - http_chunked_state_chunk_body, - http_chunked_state_done, - http_chunked_state_undefined - }; + return false; + } + static inline + std::string dec_to_hex(char num, int radix) + { + int temp = 0; + std::string csTmp; + int num_char; - blocked_mode_client_t m_net_client; - std::string m_host_buff; - std::string m_port; - unsigned int m_timeout; - std::string m_header_cache; - http_response_info m_response_info; - size_t m_len_in_summary; - size_t m_len_in_remain; - //std::string* m_ptarget_buffer; - boost::shared_ptr m_pcontent_encoding_handler; - reciev_machine_state m_state; - chunked_state m_chunked_state; - std::string m_chunked_cache; - critical_section m_lock; + num_char = (int)num; + if (num_char < 0) + num_char = 256 + num_char; - public: - void set_host_name(const std::string& name) - { - CRITICAL_REGION_LOCAL(m_lock); - m_host_buff = name; - } - - //boost::asio::ip::tcp::socket& get_socket() - //{ - // return m_net_client.get_socket(); - //} - - - bool connect(const std::string& host, int port, unsigned int timeout) + while (num_char >= radix) { - return connect(host, std::to_string(port), timeout); + temp = num_char % radix; + num_char = (int)floor((float)num_char / (float)radix); + csTmp = get_hex_vals()[temp]; } - bool connect(const std::string& host, const std::string& port, unsigned int timeout) + + csTmp += get_hex_vals()[num_char]; + + if (csTmp.size() < 2) { - CRITICAL_REGION_LOCAL(m_lock); - m_host_buff = host; - m_port = port; - m_timeout = timeout; - - return m_net_client.connect(host, port, timeout, timeout); + csTmp += '0'; } - //--------------------------------------------------------------------------- - bool disconnect() - { - CRITICAL_REGION_LOCAL(m_lock); - return m_net_client.disconnect(); - } - //--------------------------------------------------------------------------- - bool is_connected() - { - CRITICAL_REGION_LOCAL(m_lock); - return m_net_client.is_connected(); - } - //--------------------------------------------------------------------------- - virtual bool handle_target_data(std::string& piece_of_transfer) - { - CRITICAL_REGION_LOCAL(m_lock); - m_response_info.m_body += piece_of_transfer; - piece_of_transfer.clear(); - return true; - } - //--------------------------------------------------------------------------- - inline - bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) - { - CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "GET", body, ppresponse_info, additional_params); - } - //--------------------------------------------------------------------------- - inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!is_connected()) - { - LOG_PRINT("Reconnecting...", LOG_LEVEL_3); - if(!connect(m_host_buff, m_port, m_timeout)) - { - LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3); - return false; - } - } - m_response_info.clear(); - std::string req_buff = method + " "; - req_buff += uri + " HTTP/1.1\r\n" + - "Host: "+ m_host_buff +"\r\n" + "Content-Length: " + boost::lexical_cast(body.size()) + "\r\n"; + std::reverse(csTmp.begin(), csTmp.end()); + //_mbsrev((unsigned char*)csTmp.data()); + + return csTmp; + } + + static inline std::string convert(char val) + { + std::string csRet; + csRet += "%"; + csRet += dec_to_hex(val, 16); + return csRet; + } + static inline std::string conver_to_url_format(const std::string& uri) + { + + std::string result; + + for (size_t i = 0; i != uri.size(); i++) + { + if (is_unsafe(uri[i])) + result += convert(uri[i]); + else + result += uri[i]; + + } + + return result; + } + + static inline std::string convert_to_url_format_force_all(const std::string& uri) + { + + std::string result; + + for (size_t i = 0; i != uri.size(); i++) + { + result += convert(uri[i]); + } + + return result; + } - //handle "additional_params" - for(fields_list::const_iterator it = additional_params.begin(); it!=additional_params.end(); it++) - req_buff += it->first + ": " + it->second + "\r\n"; - req_buff += "\r\n"; - //-- - bool res = m_net_client.send(req_buff); - CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - if(body.size()) - res = m_net_client.send(body); - CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - if(ppresponse_info) - *ppresponse_info = &m_response_info; - m_state = reciev_machine_state_header; - return handle_reciev(); - } - //--------------------------------------------------------------------------- - inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) - { - CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "POST", body, ppresponse_info, additional_params); - } - private: - //--------------------------------------------------------------------------- - inline bool handle_reciev() - { - CRITICAL_REGION_LOCAL(m_lock); - bool keep_handling = true; - bool need_more_data = true; - std::string recv_buffer; - while(keep_handling) - { - if(need_more_data) - { - if(!m_net_client.recv(recv_buffer)) - { - LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3); - m_state = reciev_machine_state_error; - } - if(!recv_buffer.size()) - { - //connection is going to be closed - if(reciev_machine_state_body_connection_close != m_state) - { - m_state = reciev_machine_state_error; - } - } - need_more_data = false; - } - switch(m_state) - { - case reciev_machine_state_header: - keep_handling = handle_header(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_content_len: - keep_handling = handle_body_content_len(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_connection_close: - keep_handling = handle_body_connection_close(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_chunked: - keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); - break; - case reciev_machine_state_done: - keep_handling = false; - break; - case reciev_machine_state_error: - keep_handling = false; - break; - } + namespace http + { + template + class http_simple_client_t : public i_target_handler + { + public: - } - m_header_cache.clear(); - if(m_state != reciev_machine_state_error) - { - if(m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) - disconnect(); - return true; - } - else - { - LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); - return false; - } - } - //--------------------------------------------------------------------------- - inline - bool handle_header(std::string& recv_buff, bool& need_more_data) - { - - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) + private: + enum reciev_machine_state { - LOG_ERROR("Connection closed at handle_header"); - m_state = reciev_machine_state_error; - return false; + reciev_machine_state_header, + reciev_machine_state_body_content_len, + reciev_machine_state_body_connection_close, + reciev_machine_state_body_chunked, + reciev_machine_state_done, + reciev_machine_state_error + }; + + + + enum chunked_state { + http_chunked_state_chunk_head, + http_chunked_state_chunk_body, + http_chunked_state_done, + http_chunked_state_undefined + }; + + + blocked_mode_client_t m_net_client; + std::string m_host_buff; + std::string m_port; + //unsigned int m_timeout; + unsigned int m_connection_timeout; + unsigned int m_recv_timeout; + std::string m_header_cache; + http_response_info m_response_info; + //std::string* m_ptarget_buffer; + boost::shared_ptr m_pcontent_encoding_handler; + reciev_machine_state m_state; + chunked_state m_chunked_state; + std::string m_chunked_cache; + critical_section m_lock; + + protected: + uint64_t m_len_in_summary; + uint64_t m_len_in_remain; + + public: + void set_host_name(const std::string& name) + { + CRITICAL_REGION_LOCAL(m_lock); + m_host_buff = name; } - m_header_cache += recv_buff; - recv_buff.clear(); - std::string::size_type pos = m_header_cache.find("\r\n\r\n"); - if(pos != std::string::npos) - { - recv_buff.assign(m_header_cache.begin()+pos+4, m_header_cache.end()); - m_header_cache.erase(m_header_cache.begin()+pos+4, m_header_cache.end()); - - analize_cached_header_and_invoke_state(); - m_header_cache.clear(); - if(!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done)) - need_more_data = true; - - return true; - }else - need_more_data = true; - return true; - } - //--------------------------------------------------------------------------- - inline - bool handle_body_content_len(std::string& recv_buff, bool& need_more_data) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3); - m_state = reciev_machine_state_done; - return true; - } - CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); - m_len_in_remain -= recv_buff.size(); - m_pcontent_encoding_handler->update_in(recv_buff); - - if(m_len_in_remain == 0) - m_state = reciev_machine_state_done; - else - need_more_data = true; - - return true; - } - //--------------------------------------------------------------------------- - inline - bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - m_state = reciev_machine_state_done; - return true; - } - need_more_data = true; - m_pcontent_encoding_handler->update_in(recv_buff); + boost::asio::ip::tcp::socket& get_socket() + { + return m_net_client.get_socket(); + } - return true; - } - //--------------------------------------------------------------------------- - inline bool is_hex_symbol(char ch) - { + bool connect(const std::string& host, int port, unsigned int timeout) + { + return connect(host, std::to_string(port), timeout); + } - if( (ch >= '0' && ch <='9')||(ch >= 'A' && ch <='F')||(ch >= 'a' && ch <='f')) - return true; - else - return false; - } - //--------------------------------------------------------------------------- - inline - bool get_len_from_chunk_head(const std::string &chunk_head, size_t& result_size) - { - std::stringstream str_stream; - str_stream << std::hex; - if(!(str_stream << chunk_head && str_stream >> result_size)) - return false; + bool set_timeouts(unsigned int connection_timeout, unsigned int recv_timeout) + { + m_connection_timeout = connection_timeout; + m_recv_timeout = recv_timeout; + return true; + } - return true; - } - //--------------------------------------------------------------------------- - inline - bool get_chunk_head(std::string& buff, size_t& chunk_size, bool& is_matched) - { - is_matched = false; - size_t offset = 0; - for(std::string::iterator it = buff.begin(); it!= buff.end(); it++, offset++) - { - if(!is_hex_symbol(*it)) - { - if(*it == '\r' || *it == ' ' ) - { - offset--; - continue; - } - else if(*it == '\n') - { - std::string chunk_head = buff.substr(0, offset); - if(!get_len_from_chunk_head(chunk_head, chunk_size)) - return false; + bool connect(const std::string& host, std::string port) + { + CRITICAL_REGION_LOCAL(m_lock); + m_host_buff = host; + m_port = port; - if(0 == chunk_size) - { - //Here is a small confusion - //In breif - if the chunk is the last one we need to get terminating sequence - //along with the cipher, generally in the "ddd\r\n\r\n" form + return m_net_client.connect(host, port, m_connection_timeout, m_recv_timeout); + } - for(it++;it != buff.end(); it++) - { - if('\r' == *it) - continue; - else if('\n' == *it) - break; - else - { - LOG_ERROR("http_stream_filter: Wrong last chunk terminator"); - return false; - } - } + bool connect(const std::string& host, const std::string& port, unsigned int timeout) + { + m_connection_timeout = m_recv_timeout = timeout; + return connect(host, port); + } + //--------------------------------------------------------------------------- + bool disconnect() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_net_client.disconnect(); + } + //--------------------------------------------------------------------------- + bool is_connected() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_net_client.is_connected(); + } + //--------------------------------------------------------------------------- + virtual bool handle_target_data(std::string& piece_of_transfer) + { + CRITICAL_REGION_LOCAL(m_lock); + m_response_info.m_body += piece_of_transfer; + piece_of_transfer.clear(); + return true; + } + //--------------------------------------------------------------------------- + inline + bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + return invoke(uri, "GET", body, ppresponse_info, additional_params); + } - if(it == buff.end()) - return true; - } + //--------------------------------------------------------------------------- + inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!is_connected()) + { + LOG_PRINT("Reconnecting...", LOG_LEVEL_3); + if (!connect(m_host_buff, m_port)) + { + LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3); + return false; + } + } + m_response_info.clear(); + std::string req_buff = method + " "; + req_buff += uri + " HTTP/1.1\r\n" + + "Host: " + m_host_buff + "\r\n" + "Content-Length: " + boost::lexical_cast(body.size()) + "\r\n"; - buff.erase(buff.begin(), ++it); - is_matched = true; - return true; - } - else - return false; - } - } + //handle "additional_params" + for (fields_list::const_iterator it = additional_params.begin(); it != additional_params.end(); it++) + req_buff += it->first + ": " + it->second + "\r\n"; + req_buff += "\r\n"; + //-- - return true; - } - //--------------------------------------------------------------------------- - inline - bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3); - m_state = reciev_machine_state_done; - return true; - } - m_chunked_cache += recv_buff; - recv_buff.clear(); - bool is_matched = false; + bool res = m_net_client.send(req_buff); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + if (body.size()) + res = m_net_client.send(body); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - while(true) - { - if(!m_chunked_cache.size()) - { - need_more_data = true; - break; - } + if (ppresponse_info) + *ppresponse_info = &m_response_info; - switch(m_chunked_state) - { - case http_chunked_state_chunk_head: - if(m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r') - { - //optimize a bit - if(m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n') - m_chunked_cache.erase(0, 2); - else - m_chunked_cache.erase(0, 1); - break; - } - if(!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched)) - { - LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache); - m_state = reciev_machine_state_error; - return false; - } + m_state = reciev_machine_state_header; + return handle_reciev(); + } + //--------------------------------------------------------------------------- + inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + return invoke(uri, "POST", body, ppresponse_info, additional_params); + } + private: + //--------------------------------------------------------------------------- + inline bool handle_reciev() + { + CRITICAL_REGION_LOCAL(m_lock); + bool keep_handling = true; + bool need_more_data = true; + std::string recv_buffer; + while (keep_handling) + { + if (need_more_data) + { + if (!m_net_client.recv(recv_buffer)) + { + LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3); + m_state = reciev_machine_state_error; + } + if (!recv_buffer.size()) + { + //connection is going to be closed + if (reciev_machine_state_body_connection_close != m_state) + { + m_state = reciev_machine_state_error; + } + } + need_more_data = false; + } + switch (m_state) + { + case reciev_machine_state_header: + keep_handling = handle_header(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_content_len: + keep_handling = handle_body_content_len(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_connection_close: + keep_handling = handle_body_connection_close(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_chunked: + keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); + break; + case reciev_machine_state_done: + keep_handling = false; + break; + case reciev_machine_state_error: + keep_handling = false; + break; + } - if(!is_matched) - { - need_more_data = true; - return true; - }else - { - m_chunked_state = http_chunked_state_chunk_body; - if(m_len_in_remain == 0) - {//last chunk, let stop the stream and fix the chunk queue. - m_state = reciev_machine_state_done; - return true; - } - m_chunked_state = http_chunked_state_chunk_body; - break; - } - break; - case http_chunked_state_chunk_body: - { - std::string chunk_body; - if(m_len_in_remain >= m_chunked_cache.size()) - { - m_len_in_remain -= m_chunked_cache.size(); - chunk_body.swap(m_chunked_cache); - }else - { - chunk_body.assign(m_chunked_cache, 0, m_len_in_remain); - m_chunked_cache.erase(0, m_len_in_remain); - m_len_in_remain = 0; - } + } + m_header_cache.clear(); + if (m_state != reciev_machine_state_error) + { + if (m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) + disconnect(); - m_pcontent_encoding_handler->update_in(chunk_body); + return true; + } + else + { + LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); + return false; + } + } + //--------------------------------------------------------------------------- + inline + bool handle_header(std::string& recv_buff, bool& need_more_data) + { - if(!m_len_in_remain) - m_chunked_state = http_chunked_state_chunk_head; - } - break; - case http_chunked_state_done: - m_state = reciev_machine_state_done; - return true; - case http_chunked_state_undefined: - default: - LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state); - return false; - } - } + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + LOG_ERROR("Connection closed at handle_header"); + m_state = reciev_machine_state_error; + return false; + } - return true; - } - //--------------------------------------------------------------------------- - inline - bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process) - { - LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4); - - STATIC_REGEXP_EXPR_1(rexp_mach_field, - "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)" - // 12 3 4 5 6 7 8 9 - "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", - //10 1112 13 - boost::regex::icase | boost::regex::normal); + m_header_cache += recv_buff; + recv_buff.clear(); + std::string::size_type pos = m_header_cache.find("\r\n\r\n"); + if (pos != std::string::npos) + { + recv_buff.assign(m_header_cache.begin() + pos + 4, m_header_cache.end()); + m_header_cache.erase(m_header_cache.begin() + pos + 4, m_header_cache.end()); - boost::smatch result; - std::string::const_iterator it_current_bound = m_cache_to_process.begin(); - std::string::const_iterator it_end_bound = m_cache_to_process.end(); + analize_cached_header_and_invoke_state(); + m_header_cache.clear(); + if (!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done)) + need_more_data = true; + + return true; + } + else + need_more_data = true; + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_content_len(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3); + m_state = reciev_machine_state_done; + return true; + } + CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); + m_len_in_remain -= recv_buff.size(); + bool r = m_pcontent_encoding_handler->update_in(recv_buff); + //CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_pcontent_encoding_handler->update_in returned false"); + if (!r) + { + m_state = reciev_machine_state_error; + disconnect(); + return false; + } + + if (m_len_in_remain == 0) + m_state = reciev_machine_state_done; + else + need_more_data = true; + + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + m_state = reciev_machine_state_done; + return true; + } + need_more_data = true; + m_pcontent_encoding_handler->update_in(recv_buff); + + + return true; + } + //--------------------------------------------------------------------------- + inline bool is_hex_symbol(char ch) + { + + if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) + return true; + else + return false; + } + //--------------------------------------------------------------------------- + inline + bool get_len_from_chunk_head(const std::string &chunk_head, uint64_t& result_size) + { + std::stringstream str_stream; + str_stream << std::hex; + if (!(str_stream << chunk_head && str_stream >> result_size)) + return false; + + return true; + } + //--------------------------------------------------------------------------- + inline + bool get_chunk_head(std::string& buff, uint64_t& chunk_size, bool& is_matched) + { + is_matched = false; + size_t offset = 0; + for (std::string::iterator it = buff.begin(); it != buff.end(); it++, offset++) + { + if (!is_hex_symbol(*it)) + { + if (*it == '\r' || *it == ' ') + { + offset--; + continue; + } + else if (*it == '\n') + { + std::string chunk_head = buff.substr(0, offset); + if (!get_len_from_chunk_head(chunk_head, chunk_size)) + return false; + + if (0 == chunk_size) + { + //Here is a small confusion + //In breif - if the chunk is the last one we need to get terminating sequence + //along with the cipher, generally in the "ddd\r\n\r\n" form + + for (it++; it != buff.end(); it++) + { + if ('\r' == *it) + continue; + else if ('\n' == *it) + break; + else + { + LOG_ERROR("http_stream_filter: Wrong last chunk terminator"); + return false; + } + } + + if (it == buff.end()) + return true; + } + + buff.erase(buff.begin(), ++it); + + is_matched = true; + return true; + } + else + return false; + } + } + + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3); + m_state = reciev_machine_state_done; + return true; + } + m_chunked_cache += recv_buff; + recv_buff.clear(); + bool is_matched = false; + + while (true) + { + if (!m_chunked_cache.size()) + { + need_more_data = true; + break; + } + + switch (m_chunked_state) + { + case http_chunked_state_chunk_head: + if (m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r') + { + //optimize a bit + if (m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n') + m_chunked_cache.erase(0, 2); + else + m_chunked_cache.erase(0, 1); + break; + } + if (!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched)) + { + LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache); + m_state = reciev_machine_state_error; + return false; + } + + if (!is_matched) + { + need_more_data = true; + return true; + } + else + { + m_chunked_state = http_chunked_state_chunk_body; + if (m_len_in_remain == 0) + {//last chunk, let stop the stream and fix the chunk queue. + m_state = reciev_machine_state_done; + return true; + } + m_chunked_state = http_chunked_state_chunk_body; + break; + } + break; + case http_chunked_state_chunk_body: + { + std::string chunk_body; + if (m_len_in_remain >= m_chunked_cache.size()) + { + m_len_in_remain -= m_chunked_cache.size(); + chunk_body.swap(m_chunked_cache); + } + else + { + chunk_body.assign(m_chunked_cache, 0, m_len_in_remain); + m_chunked_cache.erase(0, m_len_in_remain); + m_len_in_remain = 0; + } + + m_pcontent_encoding_handler->update_in(chunk_body); + + if (!m_len_in_remain) + m_chunked_state = http_chunked_state_chunk_head; + } + break; + case http_chunked_state_done: + m_state = reciev_machine_state_done; + return true; + case http_chunked_state_undefined: + default: + LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state); + return false; + } + } + + return true; + } + //--------------------------------------------------------------------------- + inline + bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process) + { + LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4); + + STATIC_REGEXP_EXPR_1(rexp_mach_field, + "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)" + // 12 3 4 5 6 7 8 9 + "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", + //10 1112 13 + boost::regex::icase | boost::regex::normal); + + boost::smatch result; + std::string::const_iterator it_current_bound = m_cache_to_process.begin(); + std::string::const_iterator it_end_bound = m_cache_to_process.end(); - //lookup all fields and fill well-known fields - while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) - { - const size_t field_val = 12; - //const size_t field_etc_name = 10; + //lookup all fields and fill well-known fields + while (boost::regex_search(it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) + { + const size_t field_val = 12; + //const size_t field_etc_name = 10; - int i = 2; //start position = 2 - if(result[i++].matched)//"Connection" - body_info.m_connection = result[field_val]; - else if(result[i++].matched)//"Referrer" - body_info.m_referer = result[field_val]; - else if(result[i++].matched)//"Content-Length" - body_info.m_content_length = result[field_val]; - else if(result[i++].matched)//"Content-Type" - body_info.m_content_type = result[field_val]; - else if(result[i++].matched)//"Transfer-Encoding" - body_info.m_transfer_encoding = result[field_val]; - else if(result[i++].matched)//"Content-Encoding" - body_info.m_content_encoding = result[field_val]; - else if(result[i++].matched)//"Host" - { body_info.m_host = result[field_val]; - string_tools::trim(body_info.m_host); - } - else if(result[i++].matched)//"Cookie" - body_info.m_cookie = result[field_val]; - else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) - {;} - else - {CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<(result[1]); - m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); - m_response_info.m_response_code = boost::lexical_cast(result[3]); - - m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second)); - return true; - }else - { - LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache); - return false; - } + //First line response, look like this: "HTTP/1.1 200 OK" + STATIC_REGEXP_EXPR_1(rexp_match_first_response_line, "^HTTP/(\\d+).(\\d+) ((\\d)\\d{2})( [^\n]*)?\r?\n", boost::regex::icase | boost::regex::normal); + // 1 2 34 5 + //size_t match_len = 0; + boost::smatch result; + if (boost::regex_search(m_header_cache, result, rexp_match_first_response_line, boost::match_default) && result[0].matched) + { + CHECK_AND_ASSERT_MES(result[1].matched&&result[2].matched, false, "http_stream_filter::handle_invoke_reply_line() assert failed..."); + m_response_info.m_http_ver_hi = boost::lexical_cast(result[1]); + m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); + m_response_info.m_response_code = boost::lexical_cast(result[3]); - } - inline - bool set_reply_content_encoder() - { - STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal); - boost::smatch result; // 12 3 - if(boost::regex_search( m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched) - { + m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second)); + return true; + } + else + { + LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache); + return false; + } + + } + inline + bool set_reply_content_encoder() + { + STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal); + boost::smatch result; // 12 3 + if (boost::regex_search(m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched) + { #ifdef HTTP_ENABLE_GZIP - m_pcontent_encoding_handler.reset(new content_encoding_gzip(this, result[3].matched)); + m_pcontent_encoding_handler.reset(new content_encoding_gzip(this, result[3].matched)); #else - m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); - LOG_ERROR("GZIP encoding not supported in this build, please add zlib to your project and define HTTP_ENABLE_GZIP"); - return false; + m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); + LOG_ERROR("GZIP encoding not supported in this build, please add zlib to your project and define HTTP_ENABLE_GZIP"); + return false; #endif - } - else - { - m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); - } + } + else + { + m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); + } - return true; - } - inline - bool analize_cached_header_and_invoke_state() - { - m_response_info.clear(); - analize_first_response_line(); - std::string fake_str; //gcc error workaround + return true; + } + inline + bool analize_cached_header_and_invoke_state() + { + m_response_info.clear(); + analize_first_response_line(); + std::string fake_str; //gcc error workaround - bool res = parse_header(m_response_info.m_header_info, m_header_cache); - CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache); + bool res = parse_header(m_response_info.m_header_info, m_header_cache); + CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache); - set_reply_content_encoder(); + set_reply_content_encoder(); - m_len_in_summary = 0; - bool content_len_valid = false; - if(m_response_info.m_header_info.m_content_length.size()) - content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length); + m_len_in_summary = 0; + bool content_len_valid = false; + if (m_response_info.m_header_info.m_content_length.size()) + content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length); - if(!m_len_in_summary && ((m_response_info.m_response_code>=100&&m_response_info.m_response_code<200) - || 204 == m_response_info.m_response_code - || 304 == m_response_info.m_response_code) ) - {//There will be no response body, server will display the local page with error - m_state = reciev_machine_state_done; - return true; - }else if(m_response_info.m_header_info.m_transfer_encoding.size()) - { - string_tools::trim(m_response_info.m_header_info.m_transfer_encoding); - if(string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked")) - { - LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding); - m_state = reciev_machine_state_error; - return false; - } - m_state = reciev_machine_state_body_chunked; - m_chunked_state = http_chunked_state_chunk_head; - return true; - } - else if(!m_response_info.m_header_info.m_content_length.empty()) - { - //In the response header the length was specified - if(!content_len_valid) - { - LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="< + bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) { - CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); + http::url_content u_c; + bool res = parse_url(url, u_c); - if(!u_c.port) - u_c.port = 80;//default for http + if (!tr.is_connected() && !u_c.host.empty()) + { + CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); - res = tr.connect(u_c.host, static_cast(u_c.port), timeout); - CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port); + if (!u_c.port) + u_c.port = 80;//default for http + + if (!tr.connect(u_c.host, static_cast(u_c.port), timeout)) + { + LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); + return false; + } + } + + return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); } - return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); - } + struct idle_handler_base + { + virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) = 0; + virtual ~idle_handler_base() {} + }; - } -} -} + template + struct idle_handler : public idle_handler_base + { + callback_t m_cb; + + idle_handler(callback_t cb) : m_cb(cb) {} + virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) + { + return m_cb(piece_of_data, total_bytes, received_bytes); + } + }; + + class interruptible_http_client : public http_simple_client + { + std::shared_ptr m_pcb; + bool m_permanent_error = false; + + virtual bool handle_target_data(std::string& piece_of_transfer) + { + bool r = m_pcb->do_call(piece_of_transfer, m_len_in_summary, m_len_in_summary - m_len_in_remain); + piece_of_transfer.clear(); + return r; + } + + public: + template + bool invoke_cb(callback_t cb, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) + { + m_pcb.reset(new idle_handler(cb)); + const http_response_info* p_hri = nullptr; + bool r = invoke_request(url, *this, timeout, &p_hri, method, body, additional_params); + if (p_hri && !(p_hri->m_response_code >= 200 && p_hri->m_response_code < 300)) + { + LOG_PRINT_L0("HTTP request to " << url << " failed with code: " << p_hri->m_response_code); + m_permanent_error = true; + return false; + } + return r; + } + + template + bool download(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) + { + std::ofstream fs; + fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); + if (!fs.is_open()) + { + LOG_ERROR("Fsiled to open " << path_for_file); + return false; + } + auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) + { + fs.write(piece_of_data.data(), piece_of_data.size()); + return cb(total_bytes, received_bytes); + }; + bool r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params); + fs.close(); + return r; + } + + // + template + bool download_and_unzip(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), uint64_t fails_count = 1000, const fields_list& additional_params = fields_list()) + { + std::ofstream fs; + fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); + if (!fs.is_open()) + { + LOG_ERROR("Fsiled to open " << path_for_file); + return false; + } + std::string buff; + gzip_decoder_lambda zip_decoder; + uint64_t state_total_bytes = 0; + uint64_t state_received_bytes_base = 0; + uint64_t state_received_bytes_current = 0; + bool stopped = false; + auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) + { + //remember total_bytes only for first attempt, where fetched full lenght of the file + if (!state_total_bytes) + state_total_bytes = total_bytes; + + buff += piece_of_data; + return zip_decoder.update_in(buff, [&](const std::string& unpacked_buff) + { + state_received_bytes_current = received_bytes; + fs.write(unpacked_buff.data(), unpacked_buff.size()); + stopped = !cb(unpacked_buff, state_total_bytes, state_received_bytes_base + received_bytes); + return !stopped; + }); + }; + uint64_t current_err_count = 0; + bool r = false; + m_permanent_error = false; + while (!r && current_err_count < fails_count) + { + LOG_PRINT_L0("Attempt " << current_err_count + 1 << "/" << fails_count << " to get " << url << " (offset:" << state_received_bytes_base << ")"); + fields_list additional_params_local = additional_params; + additional_params_local.push_back(std::make_pair("Range", std::string("bytes=") + std::to_string(state_received_bytes_base) + "-")); + r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params_local); + if (!r) + { + if (stopped || m_permanent_error) + break; + current_err_count++; + state_received_bytes_base += state_received_bytes_current; + state_received_bytes_current = 0; + boost::this_thread::sleep_for(boost::chrono::milliseconds(2000)); + } + } + + if (current_err_count >= fails_count) + { + LOG_PRINT_YELLOW("Downloading from " << url << " FAILED as it's reached maximum (" << fails_count << ") number of attempts. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); + } + else if (m_permanent_error) + { + LOG_PRINT_YELLOW("Downloading from " << url << " FAILED due to permanent HTTP error. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); + } + + fs.close(); + return r; + } + }; + + + } // namespace http + + } // namespace net_utils +} // namespace epee \ No newline at end of file From 960daaca238cffee6ed9eb31020666df4b7d4208 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 17 Nov 2022 19:15:35 +0100 Subject: [PATCH 05/15] fixed func name --- CMakeLists.txt | 2 +- src/wallet/core_default_rpc_proxy.cpp | 2 +- src/wallet/core_default_rpc_proxy.h | 2 +- src/wallet/core_rpc_proxy.h | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af96caf1..db7b6613 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect su set(TESTNET FALSE CACHE BOOL "Compile for testnet") set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon") -include_directories(src contrib/eos_portable_archive contrib contrib/epee/include "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib") +include_directories(src contrib/eos_portable_archive contrib contrib/epee/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib") add_definitions(-DSTATICLIB) diff --git a/src/wallet/core_default_rpc_proxy.cpp b/src/wallet/core_default_rpc_proxy.cpp index 3643313e..62faa0d6 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -168,7 +168,7 @@ namespace tools return invoke_http_json_rpc_update_is_disconnect("get_pool_info", req, res); } //------------------------------------------------------------------------------------------------------------------------------ - bool default_http_core_proxy::call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) + bool default_http_core_proxy::call_COMMAND_RPC_GET_ASSET_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) { return invoke_http_json_rpc_update_is_disconnect("get_asset_info", req, res); } diff --git a/src/wallet/core_default_rpc_proxy.h b/src/wallet/core_default_rpc_proxy.h index 70ec4ea4..8a6f07aa 100644 --- a/src/wallet/core_default_rpc_proxy.h +++ b/src/wallet/core_default_rpc_proxy.h @@ -51,7 +51,7 @@ namespace tools bool call_COMMAND_RPC_GET_BLOCKS_DETAILS(const currency::COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, currency::COMMAND_RPC_GET_BLOCKS_DETAILS::response& res) override; bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res) override; bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_POOL_INFO::request& req, currency::COMMAND_RPC_GET_POOL_INFO::response& res) override; - bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) override; + bool call_COMMAND_RPC_GET_ASSET_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) override; bool check_connection() override; bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override; diff --git a/src/wallet/core_rpc_proxy.h b/src/wallet/core_rpc_proxy.h index 7154ff55..aaec5b37 100644 --- a/src/wallet/core_rpc_proxy.h +++ b/src/wallet/core_rpc_proxy.h @@ -51,6 +51,7 @@ namespace tools virtual bool call_COMMAND_RPC_GET_OFFERS_EX(const currency::COMMAND_RPC_GET_OFFERS_EX::request& req, currency::COMMAND_RPC_GET_OFFERS_EX::response& res){ return false; } virtual bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res){ return false; } virtual bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_POOL_INFO::request& req, currency::COMMAND_RPC_GET_POOL_INFO::response& res) { return false; } + virtual bool call_COMMAND_RPC_GET_ASSET_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) { return false; } i_core_proxy() { From 20bc2fdf0081c2335cc1d101adfa54792769a350 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 17 Nov 2022 20:46:21 +0100 Subject: [PATCH 06/15] fixed another tests-breaking issue --- contrib/epee/include/net/net_parse_helpers.h | 7 +++++++ src/wallet/wallet2.cpp | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contrib/epee/include/net/net_parse_helpers.h b/contrib/epee/include/net/net_parse_helpers.h index 586dac98..57f10753 100644 --- a/contrib/epee/include/net/net_parse_helpers.h +++ b/contrib/epee/include/net/net_parse_helpers.h @@ -155,6 +155,13 @@ namespace net_utils { content.port = boost::lexical_cast(result[6]); } + else + { + if (content.schema == "http") + content.port = 80; + else if (content.schema == "https") + content.port = 443; + } if(result[7].matched) { content.uri = result[7]; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2e717df9..c0365820 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3158,7 +3158,8 @@ bool wallet2::delete_custom_asset_id(const crypto::hash& asset_id) //---------------------------------------------------------------------------------------------------- bool wallet2::load_whitelisted_tokens_list() { - + epee::net_utils::http::https_simple_client https_client; + return true; } //---------------------------------------------------------------------------------------------------- void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) const From 490b8b12f1dc0393a137305fb1b8858f7a07e8da Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 17 Nov 2022 21:58:36 +0100 Subject: [PATCH 07/15] added pre-loading token whitelist via ssl --- contrib/epee/include/net/http_client.h | 46 +++++++++++++++++++ .../include/storages/http_abstract_invoke.h | 13 ++++++ src/currency_core/currency_basic.h | 18 ++++++++ src/currency_core/currency_config.h | 6 ++- src/wallet/wallet2.cpp | 10 +++- src/wallet/wallet_public_structs_defs.h | 12 +++++ 6 files changed, 103 insertions(+), 2 deletions(-) diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 76d823b9..846c5db8 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -1051,6 +1051,52 @@ namespace epee } }; + template + bool fetch_url_t(transport_t& tr, const url_content& u_c, std::string& response_body, const std::string& method = "GET", const std::string& request_body = "", unsigned int timeout = 1000) + { + fields_list additional_params; + if (!tr.is_connected() && !u_c.host.empty()) + { + if (!tr.connect(u_c.host, static_cast(u_c.port), timeout)) + { + LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); + return false; + } + } + const http_response_info* ppresponse_info = nullptr; + if (tr.invoke(u_c.uri, "GET", request_body, &ppresponse_info, additional_params) && ppresponse_info) + { + response_body = ppresponse_info->m_body; + return true; + } + return false; + } + + + bool fetch_url(const std::string& url, std::string& response_body, const std::string& method = "GET", const std::string& request_body = "", unsigned int timeout = 1000) + { + try + { + url_content u_c = AUTO_VAL_INIT(u_c); + bool res = epee::net_utils::parse_url(url, u_c); + CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); + if (u_c.schema == "https") + { + https_simple_client tr; + return fetch_url_t(tr, u_c, response_body, method, request_body, timeout); + } + else + { + http_simple_client tr; + return fetch_url_t(tr, u_c, response_body, method, request_body, timeout); + } + } + catch (...) + { + return false; + } + + } } // namespace http diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h index 0b6ef8e3..fc27faaa 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -34,6 +34,19 @@ namespace epee { namespace net_utils { + + template + bool get_http_json_t(const std::string& url, t_response& result_struct, unsigned int timeout = 5000, const std::string& method = "GET") + { + std::string body; + if (!http::fetch_url(url, body, method, "", timeout)) + { + return false; + } + return serialization::load_t_from_json(result_struct, body); + } + + template bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET") { diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index abfc69ae..59ab543a 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -770,6 +770,24 @@ namespace currency }; + struct asset_descriptor_with_id: public asset_descriptor_base + { + crypto::hash asset_id = currency::null_hash; + + /* + BEGIN_VERSIONED_SERIALIZE() + FIELD(*static_cast(this)) + FIELD(asset_id) + END_SERIALIZE() + */ + + BEGIN_KV_SERIALIZE_MAP() + KV_CHAIN_BASE(asset_descriptor_base) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + END_KV_SERIALIZE_MAP() + }; + + #define ASSET_DESCRIPTOR_OPERATION_UNDEFINED 0 #define ASSET_DESCRIPTOR_OPERATION_REGISTER 1 #define ASSET_DESCRIPTOR_OPERATION_EMMIT 2 diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 5318bc33..77b3e342 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -269,4 +269,8 @@ static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit"); static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs"); -#define CURRENCY_RELAY_TXS_MAX_COUNT 5 \ No newline at end of file +#define CURRENCY_RELAY_TXS_MAX_COUNT 5 + + +#define WALLET_ASSETS_WHITELIST_URL "https://zano.org/assets_whitelist.json" +#define WALLET_ASSETS_WHITELIST_VALIDATION_PUBLIC_KEY "" //TODO@#@ \ No newline at end of file diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c0365820..1faa8bb2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3158,7 +3158,15 @@ bool wallet2::delete_custom_asset_id(const crypto::hash& asset_id) //---------------------------------------------------------------------------------------------------- bool wallet2::load_whitelisted_tokens_list() { - epee::net_utils::http::https_simple_client https_client; + std::string body; + wallet_public::assets_whitelist aw = AUTO_VAL_INIT(aw); + if (epee::net_utils::get_http_json_t(WALLET_ASSETS_WHITELIST_URL, aw)) + { + for (auto it = aw.assets.begin(); it != aw.assets.end(); it++) + { + m_whitelisted_assets[it->asset_id] = static_cast(*it); + } + } return true; } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index f207fcd6..ad7c0e67 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -1178,6 +1178,18 @@ namespace wallet_public }; }; + struct assets_whitelist + { + std::vector assets; + crypto::signature signature = currency::null_sig; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(assets) + KV_SERIALIZE_POD_AS_HEX_STRING(signature) + END_KV_SERIALIZE_MAP() + }; + + inline std::string get_escrow_contract_state_name(uint32_t state) { switch (state) From cadb3d033a09db17eec5c017fa0520b05be37107 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 17 Nov 2022 22:00:59 +0100 Subject: [PATCH 08/15] fixed linux-specific compilation problem --- contrib/epee/include/net/net_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 8f391994..65fe6cd5 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -650,7 +650,7 @@ namespace epee class async_blocked_mode_client_t : public blocked_mode_client_t { public: - async_blocked_mode_client_t() :m_send_deadline(blocked_mode_client::m_io_service) + async_blocked_mode_client_t() :m_send_deadline(blocked_mode_client_t::m_io_service) { // No deadline is required until the first socket operation is started. We From ccc761df3a566e857a9ff114d06d5e085956cabd Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 13:19:01 +0100 Subject: [PATCH 09/15] fixed another linux-specific compilation problem --- contrib/epee/include/net/net_helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 65fe6cd5..a3a04e7a 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -668,7 +668,7 @@ namespace epee bool shutdown() { - blocked_mode_client::shutdown(); + blocked_mode_client_t::shutdown(); m_send_deadline.cancel(); return true; } @@ -753,7 +753,7 @@ namespace epee } // Put the actor back to sleep. - m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); + m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client_t::check_send_deadline, this)); } }; From 449769b229f4bee6679991c90996c060ce1d022c Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 14:00:24 +0100 Subject: [PATCH 10/15] added base class explicit specification --- contrib/epee/include/net/net_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index a3a04e7a..4361512d 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -702,7 +702,7 @@ namespace epee boost::system::error_code ec; - size_t writen = m_sct_back.get_socket().write_some(boost::asio::buffer(data, sz), ec); + size_t writen = blocked_mode_client_t::m_sct_back.get_socket().write_some(boost::asio::buffer(data, sz), ec); if (!writen || ec) { From 7c9fde7a3194f6f86bb2055b1294d59ecbc0bb38 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 14:09:42 +0100 Subject: [PATCH 11/15] added base class explicit specification to another line --- contrib/epee/include/net/net_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 4361512d..5765c162 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -745,7 +745,7 @@ namespace epee // asynchronous operations are cancelled. This allows the blocked // connect(), read_line() or write_line() functions to return. LOG_PRINT_L3("Timed out socket"); - m_sct_back.get_socket().close(); + blocked_mode_client_t::m_sct_back.get_socket().close(); // There is no longer an active deadline. The expiry is set to positive // infinity so that the actor takes no action until a new deadline is set. From 8c7aa8f578aa10f70c0aef997d68c3fe65112025 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 14:28:36 +0100 Subject: [PATCH 12/15] Updated CMakelists for openssl libs due to lates changes in base epee headers(including openssl) --- src/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index da31da22..c9178948 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,7 +124,7 @@ ENABLE_SHARED_PCH(currency_core CURRENCY_CORE) add_library(wallet ${WALLET}) if(CMAKE_SYSTEM_NAME STREQUAL "Android" ) add_dependencies(wallet version ${PCH_LIB_NAME}) - target_link_libraries(wallet currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} android log) + target_link_libraries(wallet currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} android log OpenSSL::SSL OpenSSL::Crypto) else() add_dependencies(wallet version ${PCH_LIB_NAME}) ENABLE_SHARED_PCH(wallet WALLET) @@ -158,23 +158,23 @@ add_dependencies(stratum version ${PCH_LIB_NAME}) ENABLE_SHARED_PCH(stratum STRATUM) -target_link_libraries(currency_core lmdb mdbx) +target_link_libraries(currency_core lmdb mdbx OpenSSL::SSL OpenSSL::Crypto) add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL}) add_dependencies(daemon version) -target_link_libraries(daemon rpc stratum currency_core crypto common libminiupnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(daemon rpc stratum currency_core crypto common libminiupnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(daemon DAEMON) ENABLE_SHARED_PCH_EXECUTABLE(daemon) add_executable(connectivity_tool ${CONN_TOOL}) add_dependencies(connectivity_tool version) -target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(connectivity_tool CONN_TOOL) ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool) add_executable(simplewallet ${SIMPLEWALLET}) add_dependencies(simplewallet version) -target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(simplewallet SIMPLEWALLET) ENABLE_SHARED_PCH_EXECUTABLE(simplewallet) @@ -199,7 +199,7 @@ if(BUILD_GUI) QT5_USE_MODULES(Zano WebEngineWidgets WebChannel) find_package(Qt5PrintSupport REQUIRED) - target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}OpenSSL::SSL OpenSSL::Crypto) if (UNIX AND NOT APPLE) target_link_libraries(Zano rt) endif() From bf3430b49b3979db4ea87bb7cb13e18f659d486d Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 16:11:15 +0100 Subject: [PATCH 13/15] added support of multibalances on wallets_manager and wallet rpc level --- src/wallet/view_iface.h | 6 ++-- src/wallet/wallet2.cpp | 38 ++++++++++++++++++++ src/wallet/wallet2.h | 2 ++ src/wallet/wallet_helpers.h | 3 +- src/wallet/wallet_public_structs_defs.h | 4 +-- src/wallet/wallet_rpc_server.cpp | 48 ++++++++++++------------- src/wallet/wallets_manager.cpp | 1 + 7 files changed, 68 insertions(+), 34 deletions(-) diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 3243242e..5e5a8452 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -215,8 +215,7 @@ public: struct wallet_info { - uint64_t unlocked_balance; - uint64_t balance; + std::vector balances; uint64_t mined_total; std::string address; std::string view_sec_key; @@ -225,8 +224,7 @@ public: bool is_watch_only; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(unlocked_balance) - KV_SERIALIZE(balance) + KV_SERIALIZE(balances) KV_SERIALIZE(mined_total) KV_SERIALIZE(address) KV_SERIALIZE(view_sec_key) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1faa8bb2..1ea777f9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3125,6 +3125,44 @@ bool wallet2::balance(std::unordered_map& balances, uint64_t& mined) +{ + std::unordered_map balances_map; + this->balance(balances_map, mined); + for (const auto& item : balances_map) + { + asset_descriptor_base* asset_ptr = nullptr; + //check if asset is whitelisted or customly added + auto it = m_whitelisted_assets.find(item.first); + if (it == m_whitelisted_assets.end()) + { + //check if it custom asset + auto it_cust = m_custom_assets.find(item.first); + if (it_cust == m_custom_assets.end()) + { + continue; + } + else + { + asset_ptr = &it_cust->second; + } + } + else + { + asset_ptr = &it->second; + } + + balances.push_back(wallet_public::asset_balance_entry()); + wallet_public::asset_balance_entry& new_item = balances.back(); + static_cast(new_item) = item.second; + new_item.asset_info.asset_id = item.first; + CHECK_AND_ASSERT_THROW_MES(asset_ptr, "Internal error: asset_ptr i nullptr"); + static_cast(new_item.asset_info) = *asset_ptr; + } + + return true; +} +//---------------------------------------------------------------------------------------------------- uint64_t wallet2::balance() const { uint64_t stub = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index d43650e6..58e47149 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -566,6 +566,8 @@ namespace tools uint64_t balance() const; uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined) const; bool balance(std::unordered_map& balances, uint64_t& mined) const; + bool balance(std::vector& balances, uint64_t& mined) const; + uint64_t balance(uint64_t& unloked) const; uint64_t unlocked_balance() const; diff --git a/src/wallet/wallet_helpers.h b/src/wallet/wallet_helpers.h index 9ebf9137..12a75d7a 100644 --- a/src/wallet/wallet_helpers.h +++ b/src/wallet/wallet_helpers.h @@ -16,8 +16,7 @@ namespace tools wi = AUTO_VAL_INIT_T(view::wallet_info); wi.address = w.get_account().get_public_address_str(); wi.view_sec_key = epee::string_tools::pod_to_hex(w.get_account().get_keys().view_secret_key); - uint64_t fake = 0; - wi.balance = w.balance(wi.unlocked_balance, fake, fake, wi.mined_total); + w.balance(wi.balances, wi.mined_total); wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path()); wi.is_auditable = w.is_auditable(); wi.is_watch_only = w.is_watch_only(); diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index ad7c0e67..22da411d 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -166,10 +166,10 @@ namespace wallet_public struct asset_balance_entry : public asset_balance_entry_base { - crypto::hash asset_id = currency::null_hash; + currency::asset_descriptor_with_id asset_info; //v2 BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(asset_id) + KV_SERIALIZE(asset_info) KV_CHAIN_BASE(asset_balance_entry_base) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 9ecf1008..2b4b86a1 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -112,11 +112,11 @@ namespace tools { LOG_PRINT_RED("no connection to the daemon", LOG_LEVEL_0); } - catch(std::exception& e) + catch (std::exception& e) { LOG_ERROR("exeption caught in wallet_rpc_server::idle_handler: " << e.what()); } - catch(...) + catch (...) { LOG_ERROR("unknown exeption caught in wallet_rpc_server::idle_handler"); } @@ -157,26 +157,26 @@ namespace tools //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context) { - response.m_response_code = 200; - response.m_response_comment = "Ok"; - std::string reference_stub; - bool call_found = false; + response.m_response_code = 200; + response.m_response_comment = "Ok"; + std::string reference_stub; + bool call_found = false; if (m_deaf) { - response.m_response_code = 500; - response.m_response_comment = "Internal Server Error"; + response.m_response_code = 500; + response.m_response_comment = "Internal Server Error"; return true; } if (!handle_http_request_map(query_info, response, m_conn_context, call_found, reference_stub) && response.m_response_code == 200) { - response.m_response_code = 500; - response.m_response_comment = "Internal Server Error"; + response.m_response_code = 500; + response.m_response_comment = "Internal Server Error"; return true; } if (!call_found) { - response.m_response_code = 404; - response.m_response_comment = "Not Found"; + response.m_response_code = 404; + response.m_response_comment = "Not Found"; return true; } return true; @@ -186,22 +186,18 @@ namespace tools { try { - res.balance = m_wallet.balance(); - res.unlocked_balance = m_wallet.unlocked_balance(); + // res.balance = m_wallet.balance(); + // res.unlocked_balance = m_wallet.unlocked_balance(); uint64_t mined = 0; - std::unordered_map balances; - m_wallet.balance(balances, mined); - auto it = balances.find(currency::null_hash); - if (it != balances.end()) + // std::unordered_map balances; + m_wallet.balance(res.balances, mined); + for (auto it = res.balances.begin(); it != res.balances.end(); it++) { - res.balance = it->second.total; - res.unlocked_balance = it->second.unlocked; - } - for (auto el : balances) - { - res.balances.push_back(wallet_public::asset_balance_entry()); - static_cast(res.balances.back()) = el.second; - res.balances.back().asset_id = el.first; + if (it->asset_info.asset_id == currency::null_hash) + { + res.balance = it->total; + res.unlocked_balance = it->unlocked; + } } } catch (std::exception& e) diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index f00b1d85..f238a5d6 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -943,6 +943,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st w->load(path, password); if (w->is_watch_only() && !w->is_auditable()) return API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED; + w->load_whitelisted_tokens_list(); w->get_recent_transfers_history(owr.recent_history.history, 0, txs_to_return, owr.recent_history.total_history_items, owr.recent_history.last_item_index, exclude_mining_txs); //w->get_unconfirmed_transfers(owr.recent_history.unconfirmed); From 059c367d89aeab1f0320ac15d0d09802d652ed58 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 21:04:05 +0100 Subject: [PATCH 14/15] multiple fixes over wallet and cmake --- CMakeLists.txt | 12 +++++++++--- contrib/epee/include/net/http_client.h | 2 +- src/CMakeLists.txt | 4 ++-- src/wallet/view_iface.h | 2 +- src/wallet/wallet2.cpp | 8 ++++---- src/wallet/wallet2.h | 2 +- src/wallet/wallet_rpc_server.cpp | 1 - 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db7b6613..6f2ee53a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,14 @@ PROJECT(Zano) set(VERSION "1.0") -# if(POLICY CMP0043) -# cmake_policy(SET CMP0043 OLD) -# endif() +if(POLICY CMP0043) + cmake_policy(SET CMP0043 NEW) +endif() +if(POLICY CMP0043) + cmake_policy(SET CMP0074 NEW) +endif() + + # if(POLICY CMP0020) # cmake_policy(SET CMP0020 OLD) @@ -50,6 +55,7 @@ message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}, and built ty enable_testing() +find_package(OpenSSL REQUIRED) if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10.5) diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 846c5db8..b0c8838a 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -1072,7 +1072,7 @@ namespace epee return false; } - + inline bool fetch_url(const std::string& url, std::string& response_body, const std::string& method = "GET", const std::string& request_body = "", unsigned int timeout = 1000) { try diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9178948..6b5ff732 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -158,7 +158,7 @@ add_dependencies(stratum version ${PCH_LIB_NAME}) ENABLE_SHARED_PCH(stratum STRATUM) -target_link_libraries(currency_core lmdb mdbx OpenSSL::SSL OpenSSL::Crypto) +target_link_libraries(currency_core lmdb mdbx) add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL}) add_dependencies(daemon version) @@ -199,7 +199,7 @@ if(BUILD_GUI) QT5_USE_MODULES(Zano WebEngineWidgets WebChannel) find_package(Qt5PrintSupport REQUIRED) - target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}OpenSSL::SSL OpenSSL::Crypto) + target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) if (UNIX AND NOT APPLE) target_link_libraries(Zano rt) endif() diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 5e5a8452..9a8a4e4d 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -215,7 +215,7 @@ public: struct wallet_info { - std::vector balances; + std::list balances; uint64_t mined_total; std::string address; std::string view_sec_key; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1ea777f9..1513b251 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3125,13 +3125,13 @@ bool wallet2::balance(std::unordered_map& balances, uint64_t& mined) +bool wallet2::balance(std::list& balances, uint64_t& mined) const { std::unordered_map balances_map; this->balance(balances_map, mined); for (const auto& item : balances_map) { - asset_descriptor_base* asset_ptr = nullptr; + const asset_descriptor_base* asset_ptr = nullptr; //check if asset is whitelisted or customly added auto it = m_whitelisted_assets.find(item.first); if (it == m_whitelisted_assets.end()) @@ -3154,10 +3154,10 @@ bool wallet2::balance(std::vector& balances, balances.push_back(wallet_public::asset_balance_entry()); wallet_public::asset_balance_entry& new_item = balances.back(); - static_cast(new_item) = item.second; + static_cast(new_item) = item.second; new_item.asset_info.asset_id = item.first; CHECK_AND_ASSERT_THROW_MES(asset_ptr, "Internal error: asset_ptr i nullptr"); - static_cast(new_item.asset_info) = *asset_ptr; + static_cast(new_item.asset_info) = *asset_ptr; } return true; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 58e47149..de0c60b5 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -566,7 +566,7 @@ namespace tools uint64_t balance() const; uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined) const; bool balance(std::unordered_map& balances, uint64_t& mined) const; - bool balance(std::vector& balances, uint64_t& mined) const; + bool balance(std::list& balances, uint64_t& mined) const; uint64_t balance(uint64_t& unloked) const; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 2b4b86a1..e2c953a5 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -189,7 +189,6 @@ namespace tools // res.balance = m_wallet.balance(); // res.unlocked_balance = m_wallet.unlocked_balance(); uint64_t mined = 0; - // std::unordered_map balances; m_wallet.balance(res.balances, mined); for (auto it = res.balances.begin(); it != res.balances.end(); it++) { From d4f05089cd46674bf5e54b0dacf649260ba63761 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 18 Nov 2022 22:36:07 +0100 Subject: [PATCH 15/15] added multiasset balances on UI signals --- src/wallet/view_iface.h | 10 ++-------- src/wallet/wallets_manager.cpp | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 9a8a4e4d..85bb353e 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -197,18 +197,12 @@ public: wallet_state_error = 3 }; - uint64_t balance; - uint64_t unlocked_balance; - uint64_t awaiting_in; - uint64_t awaiting_out; + std::list balances; uint64_t minied_total; BEGIN_KV_SERIALIZE_MAP() KV_CHAIN_BASE(wallet_status_info_base) - KV_SERIALIZE(balance) - KV_SERIALIZE(unlocked_balance) - KV_SERIALIZE(awaiting_in) - KV_SERIALIZE(awaiting_out) + KV_SERIALIZE(balances) KV_SERIALIZE(minied_total) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index f238a5d6..16357bb5 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1724,7 +1724,7 @@ void wallets_manager::prepare_wallet_status_info(wallet_vs_options& wo, view::wa wsi.is_mining = wo.do_mining; wsi.wallet_id = wo.wallet_id; wsi.is_alias_operations_available = !wo.has_related_alias_in_unconfirmed; - wsi.balance = wo.w->get()->balance(wsi.unlocked_balance, wsi.awaiting_in, wsi.awaiting_out, wsi.minied_total); + wo.w->get()->balance(wsi.balances, wsi.minied_total); } std::string wallets_manager::check_available_sources(uint64_t wallet_id, std::list& amounts) {