diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index f2d1abd2..318237c9 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -123,22 +123,22 @@ DISABLE_VS_WARNINGS(4100) #if defined(ENABLE_LOGGING_INTERNAL) -#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);cb(ss________.str());CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name); cb(ss________.str());CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);CATCH_ALL_DO_NOTHING();}} #define LOG_ERROR2_CB(log_name, x, cb) { \ diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index 5f002c42..3102cb2d 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -31,12 +31,20 @@ #include "http_base.h" #include "net/net_utils_base.h" + + +template +typename_t get_documentation_json_struct() +{ + return AUTO_VAL_INIT_T(typename_t); +} + template bool auto_doc_t(const std::string& prefix_name, std::string& generate_reference) { if (!generate_reference.size()) return true; - request_t req = AUTO_VAL_INIT(req); - response_t res = AUTO_VAL_INIT(res); + request_t req = get_documentation_json_struct(); + response_t res = get_documentation_json_struct(); std::stringstream ss; ss << prefix_name << ENDL << "REQUEST: " << ENDL << epee::serialization::store_t_to_json(req) << ENDL << "--------------------------------" << ENDL diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h index 417deab4..4b083804 100644 --- a/contrib/epee/include/net/http_server_impl_base.h +++ b/contrib/epee/include/net/http_server_impl_base.h @@ -65,7 +65,7 @@ namespace epee bool res = m_net_server.init_server(bind_port, bind_ip); if(!res) { - LOG_ERROR("Failed to bind server"); + LOG_ERROR("Failed to bind to " << bind_ip << ":" << bind_port); return false; } return true; @@ -74,14 +74,14 @@ namespace epee bool run(size_t threads_count, bool wait = true) { //go to loop - LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0); + LOG_PRINT("Run net_service loop (" << threads_count << " threads)...", LOG_LEVEL_1); if(!m_net_server.run_server(threads_count, wait)) { LOG_ERROR("Failed to run net tcp server!"); } if(wait) - LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_1); return true; } diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h index 4d36cc03..a5d46e19 100644 --- a/contrib/epee/include/storages/portable_storage.h +++ b/contrib/epee/include/storages/portable_storage.h @@ -77,8 +77,7 @@ namespace epee bool insert_next_section(harray hSecArray, hsection& hinserted_childsection); //------------------------------------------------------------------------ //delete entry (section, value or array) - bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr); - + bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr); //------------------------------------------------------------------------------- bool store_to_binary(binarybuffer& target); bool load_from_binary(const binarybuffer& target); @@ -87,6 +86,8 @@ namespace epee bool dump_as_json(std::string& targetObj, size_t indent = 0, end_of_line_t eol = eol_crlf); bool load_from_json(const std::string& source); + template + bool enum_entries(hsection hparent_section, cb_t cb); private: section m_root; hsection get_root_section() {return &m_root;} @@ -384,6 +385,20 @@ namespace epee CATCH_ENTRY("portable_storage::insert_first_value", nullptr); } //--------------------------------------------------------------------------------------------------------------- + template + bool portable_storage::enum_entries(hsection hparent_section, cb_t cb) + { + TRY_ENTRY(); + if (!hparent_section) hparent_section = &m_root; + for (const auto& e : hparent_section->m_entries) + { + if (!cb(e.first, e.second)) + break; + } + return true; + CATCH_ENTRY("portable_storage::enum_entries", false); + } + template bool portable_storage::insert_next_value(harray hval_array, const t_value& target) { diff --git a/contrib/epee/include/string_coding.h b/contrib/epee/include/string_coding.h index 0b125bbd..a034dec9 100644 --- a/contrib/epee/include/string_coding.h +++ b/contrib/epee/include/string_coding.h @@ -37,6 +37,7 @@ #endif #include #endif +#include #include "warnings.h" @@ -310,7 +311,14 @@ namespace string_encoding return get_md5_as_hexstring(src.data(), src.size()); } #endif - + inline + std::string toupper(std::string s) + { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return std::toupper(c); } // correct + ); + return s; + } } } diff --git a/src/common/pre_download.h b/src/common/pre_download.h index 3a3e8666..373c0bd4 100644 --- a/src/common/pre_download.h +++ b/src/common/pre_download.h @@ -21,8 +21,8 @@ namespace tools }; #ifndef TESTNET - static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_1569000.pak", "c2aff6fb65c2d7a40492738c75d1d04f2f35388d3c1a664aeb77420f2d90d644", 1740147926, 3221176320 }; - static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_1569000.pak", "f673636638b666b36c976168a3c64b2fd1fcf071c41b5d9cf01ed58a5924f80a", 2244905636, 3216977920 }; + static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2200000.pak", "c3bd64c62495c3f266759750952519f13f32fc161b59547beaa8202b6e26d516", 2628767033, 5100195840 }; + static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2200000.pak", "fcbf0ab3b23836e1a51fa675e719900fb94110cfb74790b3323cebce7fb9f5bd", 3426025872, 4954472448 }; #else static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 }; static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 }; diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index d8815803..1048c9b1 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -2646,7 +2646,7 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO } if (result_outs.outs.size() < req.decoys_count) { - LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total"); + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total", LOG_LEVEL_0); } } else @@ -2654,7 +2654,7 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO size_t added = 0; for (size_t i = 0; i != up_index_limit; i++) added += add_out_to_get_random_outs(result_outs, amount, i, req.decoys_count, req.use_forced_mix_outs, req.height_upper_limit) ? 1 : 0; - LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs"); + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs", LOG_LEVEL_0); } } return true; @@ -2889,6 +2889,51 @@ size_t blockchain_storage::get_current_sequence_factor_for_alt(alt_chain_type& a return n; } //------------------------------------------------------------------ +bool blockchain_storage::get_pos_votes(uint64_t start_index, uint64_t end_index, vote_results& r) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (start_index >= m_db_blocks.size() || start_index >= end_index) + { + //LOG_PRINT_L0("Wrong starter or end index set: start_index = " << start_index << ", end_index=" << end_index << ", expected max index " << m_db_blocks.size() - 1); + return true; + } + std::map summary; + + for (size_t i = start_index; i < m_db_blocks.size() && i < end_index; i++) + { + auto block_ptr = m_db_blocks[i]; + //only coin holders can vote + if(!is_pos_block(block_ptr->bl)) + continue; + r.total_pos_blocks++; + + extra_user_data eud = AUTO_VAL_INIT(eud); + if (!get_type_in_variant_container(block_ptr->bl.miner_tx.extra, eud)) + { + continue; + } + std::list> votes; + if (!currency::parse_vote(eud.buff, votes)) + { + continue; + } + for (const auto& v : votes) + { + if (v.second) + summary[v.first].yes++; + else + summary[v.first].no++; + } + } + for (const auto s_entry : summary) + { + r.votes.push_back(s_entry.second); + r.votes.back().proposal_id = s_entry.first; + } + + return true; +} +//------------------------------------------------------------------ std::string blockchain_storage::get_blockchain_string(uint64_t start_index, uint64_t end_index) const { std::stringstream ss; diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 6b28166c..118d59b8 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -457,6 +457,7 @@ namespace currency void serialize(archive_t & ar, const unsigned int version); bool get_est_height_from_date(uint64_t date, uint64_t& res_h)const; + bool get_pos_votes(uint64_t start_h, uint64_t end_h, vote_results& r); //debug functions bool validate_blockchain_prev_links(size_t last_n_blocks_to_check = 10) const; diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index e997b58f..0ecf53bd 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -159,6 +159,28 @@ namespace currency transactions_map onboard_transactions; }; + struct vote_on_proposal + { + std::string proposal_id; + uint64_t yes; + uint64_t no; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(proposal_id) + KV_SERIALIZE(yes) + KV_SERIALIZE(no) + END_KV_SERIALIZE_MAP() + }; + + struct vote_results + { + uint64_t total_pos_blocks; //total pos blocks in a given range + std::list votes; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(total_pos_blocks) + KV_SERIALIZE(votes) + END_KV_SERIALIZE_MAP() + }; } // namespace currency diff --git a/src/currency_core/checkpoints_create.h b/src/currency_core/checkpoints_create.h index e0152685..49d10037 100644 --- a/src/currency_core/checkpoints_create.h +++ b/src/currency_core/checkpoints_create.h @@ -26,6 +26,7 @@ namespace currency ADD_CHECKPOINT(900000, "2205b73cd79d4937b087b02a8b001171b73c34464bc4a952834eaf7c2bd63e86"); ADD_CHECKPOINT(1161000, "96990d851b484e30190678756ba2a4d3a2f92b987e2470728ac1e38b2bf35908"); ADD_CHECKPOINT(1480000, "5dd3381eec35e8b4eba4518bfd8eec682a4292761d92218fd59b9f0ffedad3fe"); + ADD_CHECKPOINT(2000000, "7b6698a8cc279aa78d6263f01fef186bd16f5b1ea263a7f4714abc1d506b9cb3"); #endif return true; diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 84436bbb..8944a143 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -36,6 +36,8 @@ #define HF3_BLOCK_MINOR_VERSION 0 #define CURRENT_BLOCK_MAJOR_VERSION 3 +#define CURRENCY_DEFAULT_DECOY_SET_SIZE 10 + #define CURRENT_BLOCK_MINOR_VERSION 0 #define CURRENCY_BLOCK_FUTURE_TIME_LIMIT 60*60*2 #define CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT 60*20 @@ -230,6 +232,7 @@ #define GUI_INTERNAL_CONFIG2 "gui_internal_config.json" #define GUI_IPC_MESSAGE_CHANNEL_NAME CURRENCY_NAME_BASE "_message_que" +#define CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME "voting_config.json" #define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3 diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 7b4ca62d..112ad3ad 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -504,6 +504,15 @@ namespace currency //----------------------------------------------------------------------------------------------- bool core::add_new_block(const block& b, block_verification_context& bvc) { + uint64_t h = m_blockchain_storage.get_top_block_height(); + if (m_stop_after_height != 0 && h >= m_stop_after_height) + { + LOG_PRINT_YELLOW("Blockchain top block height is " << h << ", the daemon will now stop as requested", LOG_LEVEL_0); + if (m_critical_error_handler) + return m_critical_error_handler->on_immediate_stop_requested(); + return false; + } + bool r = m_blockchain_storage.add_new_block(b, bvc); if (r && bvc.m_added_to_main_chain) { diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index c07fc4f3..87bd14bb 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -2751,6 +2751,35 @@ namespace currency return timestamp; } //--------------------------------------------------------------- + bool parse_vote(const std::string& json_, std::list>& votes) + { + //do preliminary check of text if it looks like json + std::string::size_type pos = json_.find('{'); + if (pos == std::string::npos) + return false; + std::string json = json_.substr(pos); + + epee::serialization::portable_storage ps; + bool rs = ps.load_from_json(json); + if (!rs) + return false; + + + + auto cb = [&](const std::string& name, const epee::serialization::storage_entry& entry) { + if (entry.type() == typeid(uint64_t)) + { + bool vote = boost::get(entry) ? true : false; + votes.push_back(std::make_pair(epee::string_encoding::toupper(name), vote)); + } + return true; + }; + + ps.enum_entries(nullptr, cb); + return true; + + } + //--------------------------------------------------------------- bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed /* = nullptr */) { #define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, msg << ", ms input index: " << ms_input_index << ", tx: " << get_transaction_hash(tx) << ", source tx: " << get_transaction_hash(source_tx)) diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 5baad2aa..e30c40dd 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -446,7 +446,10 @@ namespace currency bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h); void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map& gindices); std::string get_word_from_timstamp(uint64_t timestamp, bool use_password); + uint64_t get_timstamp_from_word(std::string word, bool& password_used, const std::string& buff); uint64_t get_timstamp_from_word(std::string word, bool& password_used); + bool parse_vote(const std::string& buff, std::list>& votes); + std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys); bool validate_ado_update_allowed(const asset_descriptor_base& a, const asset_descriptor_base& b); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 7c36e0ee..eb5af1ac 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -669,6 +669,18 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_votes(const COMMAND_RPC_GET_VOTES::request& req, COMMAND_RPC_GET_VOTES::response& res, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_pos_votes(req.h_start, req.h_end, res.votes)) + { + res.status = API_RETURN_CODE_INTERNAL_ERROR; + res.error_code = "Internal error"; + return true; + } + res.status = API_RETURN_CODE_OK; + 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)) diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index ba08319a..3bf44fcf 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -83,6 +83,7 @@ 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_votes(const COMMAND_RPC_GET_VOTES::request& req, COMMAND_RPC_GET_VOTES::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); @@ -139,6 +140,7 @@ 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) + MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES) //assets api MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 885fa313..450a1a8f 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -82,6 +82,33 @@ namespace currency }; }; + struct COMMAND_RPC_GET_VOTES + { + struct request + { + uint64_t h_start; + uint64_t h_end; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(h_start) + KV_SERIALIZE(h_end) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::string error_code; + vote_results votes; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(error_code) + KV_SERIALIZE(votes) + END_KV_SERIALIZE_MAP() + }; + }; + struct asset_id_kv { crypto::public_key asset_id; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index e3ce4e54..ce4eed61 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -130,14 +130,16 @@ namespace const command_line::arg_descriptor arg_dont_refresh ( "no-refresh", "Do not refresh after load"); const command_line::arg_descriptor arg_dont_set_date ( "no-set-creation-date", "Do not set wallet creation date", false); const command_line::arg_descriptor arg_daemon_port ("daemon-port", "Use daemon instance at port instead of default", 0); - const command_line::arg_descriptor arg_log_level ("set-log", ""); + //const command_line::arg_descriptor arg_log_level ("set-log", ""); const command_line::arg_descriptor arg_do_pos_mining ( "do-pos-mining", "Do PoS mining", false); const command_line::arg_descriptor arg_pos_mining_reward_address ( "pos-mining-reward-address", "Block reward will be sent to the giving address if specified", "" ); const command_line::arg_descriptor arg_restore_wallet ( "restore-wallet", "Restore wallet from seed phrase or tracking seed and save it to ", "" ); const command_line::arg_descriptor arg_offline_mode ( "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)"); const command_line::arg_descriptor arg_scan_for_wallet ( "scan-for-wallet", ""); const command_line::arg_descriptor arg_addr_to_compare ( "addr-to-compare", ""); - const command_line::arg_descriptor arg_disable_tor_relay ( "disable-tor-relay", "Do PoS mining", false); + const command_line::arg_descriptor arg_disable_tor_relay ( "disable-tor-relay", "Disable TOR relay", false); + const command_line::arg_descriptor arg_set_timeout("set-timeout", "Set timeout for the wallet"); + const command_line::arg_descriptor arg_voting_config_file("voting-config-file", "Set voting config instead of getting if from daemon", ""); const command_line::arg_descriptor< std::vector > arg_command ("command", ""); @@ -239,6 +241,26 @@ namespace } } +void display_vote_info(tools::wallet2& w) +{ + const tools::wallet_public::wallet_vote_config& votes = w.get_current_votes(); + if (votes.entries.size()) + { + message_writer(epee::log_space::console_color_magenta, true) << "VOTING SET LOADED:"; + for (const auto& e : votes.entries) + { + epee::log_space::console_colors color = epee::log_space::console_color_green; + if (e.h_end < w.get_top_block_height()) + { + color = epee::log_space::console_color_white; + } + + message_writer(color, true) << "\t\t" << e.proposal_id << "\t\t" << (e.vote ? "1" : "0") << "\t\t(" << e.h_start << " - " << e.h_end << ")"; + } + } +} + + std::string simple_wallet::get_commands_str() { std::stringstream ss; @@ -264,7 +286,8 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, ph::_1), "start_mining - Start mining in daemon"); m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon"); m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance"); - m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "Show current wallet balance"); + m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "Show current wallet balance"); + m_cmd_binder.set_handler("show_staking_history", boost::bind(&simple_wallet::show_staking_history, this, ph::_1), "show_staking_history [2] - Show staking transfers, if option provided - number of days for history to display"); m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, ph::_1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability"); m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, ph::_1), "incoming_transfers counts"); m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, ph::_1), "list_recent_transfers [offset] [count] - Show recent maximum 1000 transfers, offset default = 0, count default = 100 "); @@ -355,6 +378,29 @@ bool simple_wallet::set_log(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- +void process_wallet_command_line_params(const po::variables_map& vm, tools::wallet2& wal, bool is_server_mode = true) +{ + if (command_line::has_arg(vm, arg_disable_tor_relay)) + { + wal.set_disable_tor_relay(command_line::get_arg(vm, arg_disable_tor_relay)); + message_writer(epee::log_space::console_color_default, true, std::string(), LOG_LEVEL_0) << "Notice: Relaying transactions over TOR disabled with command line parameter"; + } + else + { + if (is_server_mode) + { + //disable TOR by default for server-mode, to avoid potential sporadic errors due to TOR connectivity fails + wal.set_disable_tor_relay(true); + } + } + + if (command_line::has_arg(vm, arg_set_timeout)) + { + wal.set_connectivity_options(command_line::get_arg(vm, arg_set_timeout)); + } + +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::init(const boost::program_options::variables_map& vm) { handle_command_line(vm); @@ -399,7 +445,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) m_do_refresh_after_load = false; } - + bool was_open = false; if (!m_generate_new.empty()) { bool r = new_wallet(m_generate_new, pwd_container.password(), false); @@ -450,12 +496,14 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) { bool r = open_wallet(m_wallet_file, pwd_container.password()); CHECK_AND_ASSERT_MES(r, false, "could not open account"); + was_open = true; } - if (m_disable_tor) - { - m_wallet->set_disable_tor_relay(true); - message_writer(epee::log_space::console_color_default, true, std::string(), LOG_LEVEL_0) << "Notice: Relaying transactions over TOR disabled with command line parameter"; - } + process_wallet_command_line_params(vm, *m_wallet, false); + + m_wallet->init(m_daemon_address); + + if (was_open && (m_do_refresh_after_load && !m_offline_mode)) + refresh(std::vector()); return true; } @@ -480,6 +528,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_ m_do_pos_mining = command_line::get_arg(vm, arg_do_pos_mining); m_restore_wallet = command_line::get_arg(vm, arg_restore_wallet); m_disable_tor = command_line::get_arg(vm, arg_disable_tor_relay); + m_voting_config_file = command_line::get_arg(vm, arg_voting_config_file); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::try_connect_to_daemon() @@ -500,18 +549,21 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas m_wallet.reset(new tools::wallet2()); m_wallet->callback(this->shared_from_this()); + if (!m_voting_config_file.empty()) + m_wallet->set_votes_config_path(m_voting_config_file); + m_wallet->set_do_rise_transfer(false); try { m_wallet->generate(epee::string_encoding::utf8_to_wstring(m_wallet_file), password, create_auditable_wallet); message_writer(epee::log_space::console_color_white, true) << "Generated new " << (create_auditable_wallet ? "AUDITABLE" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); + display_vote_info(*m_wallet); std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; if (m_wallet->is_auditable()) std::cout << "tracking seed: " << std::endl << m_wallet->get_account().get_tracking_seed() << std::endl << std::flush; if (m_do_not_set_date) m_wallet->reset_creation_time(0); - } catch (const std::exception& e) { @@ -519,9 +571,6 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas return false; } - m_wallet->init(m_daemon_address); - - success_msg_writer() << "**********************************************************************\n" << "Your wallet has been generated.\n" << @@ -535,6 +584,9 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st m_wallet.reset(new tools::wallet2()); m_wallet->callback(this->shared_from_this()); + if (!m_voting_config_file.empty()) + m_wallet->set_votes_config_path(m_voting_config_file); + m_wallet->set_do_rise_transfer(true); try { @@ -553,6 +605,7 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st if (m_wallet->is_auditable()) std::cout << "tracking seed: " << std::endl << m_wallet->get_account().get_tracking_seed() << std::endl << std::flush; } + display_vote_info(*m_wallet); if (m_do_not_set_date) m_wallet->reset_creation_time(0); } @@ -566,7 +619,6 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st fail_msg_writer() << "failed to restore wallet, check your " << (tracking_wallet ? "tracking seed!" : "seed phrase!") << ENDL; return false; } - m_wallet->init(m_daemon_address); success_msg_writer() << "**********************************************************************\n" << @@ -580,11 +632,15 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st return true; } //---------------------------------------------------------------------------------------------------- + bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password) { m_wallet_file = wallet_file; m_wallet.reset(new tools::wallet2()); m_wallet->callback(shared_from_this()); + if (!m_voting_config_file.empty()) + m_wallet->set_votes_config_path(m_voting_config_file); + while (true) { @@ -592,6 +648,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa { m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password); message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); + display_vote_info(*m_wallet); break; } @@ -608,12 +665,6 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa } } - - m_wallet->init(m_daemon_address); - - if (m_do_refresh_after_load && !m_offline_mode) - refresh(std::vector()); - success_msg_writer() << "**********************************************************************\n" << "Use \"help\" command to see the list of available commands.\n" << @@ -986,15 +1037,13 @@ bool simple_wallet::list_recent_transfers(const std::vector& args) success_msg_writer() << "Unconfirmed transfers: "; for (auto & wti : unconfirmed) { - if (!wti.fee) - wti.fee = currency::get_tx_fee(wti.tx); + wti.fee = currency::get_tx_fee(wti.tx); print_wti(wti); } success_msg_writer() << "Recent transfers: "; for (auto & wti : recent) { - if (!wti.fee) - wti.fee = currency::get_tx_fee(wti.tx); + wti.fee = currency::get_tx_fee(wti.tx); print_wti(wti); } return true; @@ -1066,6 +1115,70 @@ bool simple_wallet::dump_key_images(const std::vector& args) success_msg_writer() << "Storing text to dump_keyimages.txt...."; file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/dump_keyimages.txt", ss.str()); success_msg_writer() << "Done...."; + return true; +} +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::show_staking_history(const std::vector& args) +{ + uint64_t n_days = 0; + if (!args.empty()) + { + if (!epee::string_tools::get_xtype_from_string(n_days, args[0])) + { + fail_msg_writer() << "Unknown amount of days to list"; + return true; + } + } + + tools::wallet2::transfer_container transfers; + m_wallet->get_transfers(transfers); + + uint64_t timestamp = 0; + + if (n_days) + timestamp = static_cast(time(nullptr)) - (n_days * 60 * 60 * 24); + + uint64_t amount_total_staked = 0; + bool transfers_found = false; + for (auto it = transfers.rbegin(); it != transfers.rend(); it++) + { + const auto& td = *it; + + if (timestamp && td.m_ptx_wallet_info->m_block_timestamp < timestamp) + break; + + if (!(td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER)) + continue; + + bool pos_coinbase = false; + is_coinbase(td.m_ptx_wallet_info->m_tx, pos_coinbase); + if (!pos_coinbase) + continue; + + if (!transfers_found) + { + message_writer() << " amount \tspent\tglobal index\t tx id"; + transfers_found = true; + } + amount_total_staked += td.amount(); + message_writer(static_cast(td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT) ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, false) << + std::setw(21) << print_money(td.amount()) << '\t' << + std::setw(3) << (static_cast(td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT) ? 'T' : 'F') << " \t" << + std::setw(12) << td.m_global_output_index << '\t' << + get_transaction_hash(td.m_ptx_wallet_info->m_tx) << "[" << td.m_ptx_wallet_info->m_block_height << "] unlocked: " << (m_wallet->is_transfer_unlocked(td) ? 'T' : 'F'); + } + + if (!transfers_found) + { + success_msg_writer() << "No staking transactions"; + } + else + { + success_msg_writer() << "Total staked: " << print_money(amount_total_staked); + } + + + return true; } //---------------------------------------------------------------------------------------------------- @@ -2447,6 +2560,7 @@ bool search_for_wallet_file(const std::wstring &search_here/*, const std::string } return false; } + //---------------------------------------------------------------------------------------------------- #ifdef WIN32 int wmain( int argc, wchar_t* argv_w[ ], wchar_t* envp[ ] ) @@ -2495,7 +2609,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_daemon_host); command_line::add_arg(desc_params, arg_daemon_port); command_line::add_arg(desc_params, arg_command); - command_line::add_arg(desc_params, arg_log_level); + //command_line::add_arg(desc_params, arg_log_level); command_line::add_arg(desc_params, arg_dont_refresh); command_line::add_arg(desc_params, arg_dont_set_date); command_line::add_arg(desc_params, arg_do_pos_mining); @@ -2507,6 +2621,9 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_scan_for_wallet); command_line::add_arg(desc_params, arg_addr_to_compare); command_line::add_arg(desc_params, arg_disable_tor_relay); + command_line::add_arg(desc_params, arg_set_timeout); + command_line::add_arg(desc_params, arg_voting_config_file); + tools::wallet_rpc_server::init_options(desc_params); @@ -2544,7 +2661,7 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; //set up logging options - log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); boost::filesystem::path log_file_path(command_line::get_arg(vm, command_line::arg_log_file)); if (log_file_path.empty()) log_file_path = log_space::log_singletone::get_default_log_file(); @@ -2553,15 +2670,13 @@ int main(int argc, char* argv[]) log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str(), LOG_LEVEL_4); message_writer(epee::log_space::console_color_white, true) << CURRENCY_NAME << " wallet v" << PROJECT_VERSION_LONG; - if (command_line::has_arg(vm, arg_log_level)) - { - LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level)); - log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level)); - } if (command_line::has_arg(vm, command_line::arg_log_level)) { - LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, command_line::arg_log_level)); - log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, command_line::arg_log_level)); + int old_log_level = log_space::get_set_log_detalisation_level(false); + int new_log_level = command_line::get_arg(vm, command_line::arg_log_level); + log_space::get_set_log_detalisation_level(true, new_log_level); + LOG_PRINT_L0("Log level changed: " << old_log_level << " -> " << new_log_level); + message_writer(epee::log_space::console_color_white, true) << "Log level changed: " << old_log_level << " -> " << new_log_level; } @@ -2582,7 +2697,7 @@ int main(int argc, char* argv[]) // runs wallet as RPC server log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); sw->set_offline_mode(offline_mode); - LOG_PRINT_L0("Starting wallet RPC server..."); + LOG_PRINT_L0("Starting in RPC server mode..."); if (!command_line::has_arg(vm, arg_wallet_file) || command_line::get_arg(vm, arg_wallet_file).empty()) { @@ -2649,7 +2764,9 @@ int main(int argc, char* argv[]) try { LOG_PRINT_L0("Initializing wallet..."); + process_wallet_command_line_params(vm, wal); wal.init(daemon_address); + display_vote_info(wal); if (command_line::get_arg(vm, arg_generate_new_wallet).size() || command_line::get_arg(vm, arg_generate_new_auditable_wallet).size()) return EXIT_FAILURE; @@ -2680,6 +2797,8 @@ int main(int argc, char* argv[]) LOG_PRINT_YELLOW("PoS reward will be sent to another address: " << arg_pos_mining_reward_address_str, LOG_LEVEL_0); } } + + tools::wallet_rpc_server wrpc(wallet_ptr); bool r = wrpc.init(vm); @@ -2708,7 +2827,7 @@ int main(int argc, char* argv[]) if (command_line::get_arg(vm, arg_do_pos_mining)) { // PoS mining can be turned on only in RPC server mode, please provide --rpc-bind-port to make this - fail_msg_writer() << "PoS mining can be turned on only in RPC server mode, please provide --rpc-bind-port=PORT_NO to enable staking in simplewallet"; + fail_msg_writer() << "PoS mining can only be started in RPC server mode, please use command-line option --rpc-bind-port= along with --do-pos-mining to enable staking"; return EXIT_FAILURE; } diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 82400621..8f353bcf 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -59,6 +59,7 @@ namespace currency bool dump_trunsfers(const std::vector& args); bool dump_key_images(const std::vector& args); bool show_incoming_transfers(const std::vector &args); + bool show_staking_history(const std::vector& args); bool show_incoming_transfers_counts(const std::vector &args); bool list_outputs(const std::vector &args); bool show_payments(const std::vector &args); @@ -187,6 +188,7 @@ namespace currency bool m_offline_mode; bool m_disable_tor; std::string m_restore_wallet; + std::string m_voting_config_file; epee::console_handlers_binder m_cmd_binder; diff --git a/src/wallet/core_default_rpc_proxy.cpp b/src/wallet/core_default_rpc_proxy.cpp index 62faa0d6..8e0638c5 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -184,11 +184,10 @@ namespace tools // m_plast_daemon_is_disconnected = plast_daemon_is_disconnected ? plast_daemon_is_disconnected : &m_last_daemon_is_disconnected_stub; // } //------------------------------------------------------------------------------------------------------------------------------ - bool default_http_core_proxy::set_connectivity(unsigned int connection_timeout, size_t repeats_count) + void default_http_core_proxy::set_connectivity(unsigned int connection_timeout, size_t repeats_count) { m_connection_timeout = connection_timeout; m_attempts_count = repeats_count; - return true; } //------------------------------------------------------------------------------------------------------------------------------ default_http_core_proxy::default_http_core_proxy(): //:m_plast_daemon_is_disconnected(&m_last_daemon_is_disconnected_stub), diff --git a/src/wallet/core_default_rpc_proxy.h b/src/wallet/core_default_rpc_proxy.h index 8a6f07aa..f344bfd9 100644 --- a/src/wallet/core_default_rpc_proxy.h +++ b/src/wallet/core_default_rpc_proxy.h @@ -28,7 +28,7 @@ namespace tools bool set_connection_addr(const std::string& url) override; - bool set_connectivity(unsigned int connection_timeout, size_t repeats_count); + void set_connectivity(unsigned int connection_timeout, size_t repeats_count); bool call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(const currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& rqt, currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& rsp) override; bool call_COMMAND_RPC_GET_BLOCKS_FAST(const currency::COMMAND_RPC_GET_BLOCKS_FAST::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_FAST::response& rsp) override; bool call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::COMMAND_RPC_GET_BLOCKS_DIRECT::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& rsp) override; @@ -56,7 +56,7 @@ namespace tools bool check_connection() override; bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override; - void set_plast_daemon_is_disconnected(std::atomic *plast_daemon_is_disconnected); + void set_plast_daemon_is_disconnected(std::atomic *plast_daemon_is_disconnected); default_http_core_proxy(); private: diff --git a/src/wallet/core_rpc_proxy.h b/src/wallet/core_rpc_proxy.h index aaec5b37..747e06e2 100644 --- a/src/wallet/core_rpc_proxy.h +++ b/src/wallet/core_rpc_proxy.h @@ -63,6 +63,7 @@ namespace tools std::shared_ptr get_proxy_diagnostic_info() const { return m_pdiganostic_info; } std::shared_ptr get_editable_proxy_diagnostic_info() { return m_pdiganostic_info; } virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id){ return false; } + virtual void set_connectivity(unsigned int connection_timeout, size_t repeats_count) {} protected: std::shared_ptr m_pdiganostic_info; }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index fa91f698..1290f971 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -23,6 +23,7 @@ using namespace epee; #include "currency_core/bc_offers_service_basic.h" #include "rpc/core_rpc_server_commands_defs.h" #include "misc_language.h" +#include "common/util.h" #include "common/boost_serialization_helper.h" #include "crypto/crypto.h" @@ -70,6 +71,7 @@ namespace tools , m_do_rise_transfer(false) , m_log_prefix("???") , m_watch_only(false) + , m_required_decoys_count(CURRENCY_DEFAULT_DECOY_SET_SIZE) , m_min_utxo_count_for_defragmentation_tx(WALLET_MIN_UTXO_COUNT_FOR_DEFRAGMENTATION_TX) , m_max_utxo_count_for_defragmentation_tx(WALLET_MAX_UTXO_COUNT_FOR_DEFRAGMENTATION_TX) , m_decoys_count_for_defragmentation_tx(WALLET_DEFAULT_DECOYS_COUNT_FOR_DEFRAGMENTATION_TX) @@ -79,6 +81,7 @@ namespace tools #else , m_disable_tor_relay(false) #endif + , m_votes_config_path(tools::get_default_data_dir() + "/" + CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME) { m_core_runtime_config = currency::get_default_core_runtime_config(); } @@ -135,9 +138,22 @@ std::string wallet2::transfer_flags_to_str(uint32_t flags) //---------------------------------------------------------------------------------------------------- void wallet2::init(const std::string& daemon_address) { - m_miner_text_info = PROJECT_VERSION_LONG; + //m_miner_text_info = PROJECT_VERSION_LONG; m_core_proxy->set_connection_addr(daemon_address); m_core_proxy->check_connection(); + + std::stringstream ss; + const tools::wallet_public::wallet_vote_config& votes = this->get_current_votes(); + if (votes.entries.size()) + { + ss << "VOTING SET LOADED:"; + for (const auto& e : votes.entries) + { + ss << "\t\t" << e.proposal_id << "\t\t" << (e.vote ? "1" : "0") << "\t\t(" << e.h_start << " - " << e.h_end << ")"; + } + } + WLT_LOG_L0(ss.str()); + } //---------------------------------------------------------------------------------------------------- bool wallet2::set_core_proxy(const std::shared_ptr& proxy) @@ -1734,7 +1750,7 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup const std::vector* pglobal_index = nullptr; - if (b.timestamp + 60 * 60 * 24 > m_account.get_createtime()) + if (get_block_height(b) > get_wallet_minimum_height()) // b.timestamp + 60 * 60 * 24 > m_account.get_createtime()) { pglobal_index = nullptr; if (bche.coinbase_ptr.get()) @@ -2996,6 +3012,19 @@ bool wallet2::check_connection() return m_core_proxy->check_connection(); } //---------------------------------------------------------------------------------------------------- +void wallet2::set_votes_config_path(const std::string& path_to_config_file/* = tools::get_default_data_dir() + "\voting_config.json"*/) +{ + m_votes_config_path = path_to_config_file; +} +//---------------------------------------------------------------------------------------------------- +void wallet2::load_votes_config() +{ + if (boost::filesystem::exists(m_votes_config_path)) + { + epee::serialization::load_t_from_json_file(m_votes_config, m_votes_config_path); + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::load(const std::wstring& wallet_, const std::string& password) { clear(); @@ -3034,7 +3063,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) { // old WALLET_FILE_BINARY_HEADER_VERSION version means no encryption need_to_resync = !tools::portable_unserialize_obj_from_stream(*this, data_file); - WLT_LOG_L0("Detected format: WALLET_FILE_BINARY_HEADER_VERSION_INITAL(need_to_resync=" << need_to_resync << ")"); + WLT_LOG_L1("Detected format: WALLET_FILE_BINARY_HEADER_VERSION_INITAL (need_to_resync=" << need_to_resync << ")"); } else if (wbh.m_ver == WALLET_FILE_BINARY_HEADER_VERSION_2) { @@ -3043,7 +3072,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) in.push(decrypt_filter); in.push(data_file); need_to_resync = !tools::portable_unserialize_obj_from_stream(*this, in); - WLT_LOG_L0("Detected format: WALLET_FILE_BINARY_HEADER_VERSION_2(need_to_resync=" << need_to_resync << ")"); + WLT_LOG_L1("Detected format: WALLET_FILE_BINARY_HEADER_VERSION_2 (need_to_resync=" << need_to_resync << ")"); } else { @@ -3064,10 +3093,11 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) << ", file_size=" << m_current_wallet_file_size << ", blockchain_size: " << m_chain.get_blockchain_current_size() ); - WLT_LOG_L0("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); + WLT_LOG_L1("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); + load_votes_config(); - WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")"); + WLT_LOG_L1("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")"); if (need_to_resync) { @@ -3139,7 +3169,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor boost::uintmax_t tmp_file_size = boost::filesystem::file_size(tmp_file_path); WLT_LOG_L0("Stored successfully to temporary file " << tmp_file_path.string() << ", file size=" << tmp_file_size); - WLT_LOG_L0("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); + WLT_LOG_L1("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); // for the sake of safety perform a double-renaming: wallet file -> old tmp, new tmp -> wallet file, remove old tmp @@ -3941,7 +3971,11 @@ void wallet2::wti_to_json_line(std::ostream& ss, const wallet_public::wallet_tra ss << epee::serialization::store_t_to_json(wti, 4) << ","; }; - +//---------------------------------------------------------------------------------------------------- +void wallet2::set_connectivity_options(unsigned int timeout) +{ + m_core_proxy->set_connectivity(timeout, WALLET_RCP_COUNT_ATTEMNTS); +} //---------------------------------------------------------------------------------------------------- void wallet2::export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions) { @@ -4113,26 +4147,100 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful txin_to_key& stake_input = boost::get(b.miner_tx.vin[1]); const txout_to_key& stake_out_target = boost::get(stake_out.target); - // fill stake input + // partially fill stake input stake_input.k_image = pe.keyimage; stake_input.amount = pe.amount; - stake_input.key_offsets.push_back(pe.g_index); + + // get decoys outputs and construct miner tx + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response decoys_resp = AUTO_VAL_INIT(decoys_resp); + std::vector ring; + uint64_t secret_index = 0; // index of the real stake output + if (m_required_decoys_count > 0) + { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request decoys_req = AUTO_VAL_INIT(decoys_req); + decoys_req.height_upper_limit = 0; // TODO @#@# maybe use m_last_pow_block_h like Zarcanum? + decoys_req.use_forced_mix_outs = false; + decoys_req.decoys_count = m_required_decoys_count + 1; // one more to be able to skip a decoy in case it hits the real output + decoys_req.amounts.push_back(pe.amount); // request one batch of decoys + + r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(decoys_req, decoys_resp); + // TODO @#@# do we need these exceptions? + THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs.bin"); + THROW_IF_FALSE_WALLET_EX(decoys_resp.status != API_RETURN_CODE_BUSY, error::daemon_busy, "getrandom_outs.bin"); + THROW_IF_FALSE_WALLET_EX(decoys_resp.status == API_RETURN_CODE_OK, error::get_random_outs_error, decoys_resp.status); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(decoys_resp.outs.size() == 1, "got wrong number of decoys batches: " << decoys_resp.outs.size()); + + // we expect that less decoys can be returned than requested, we will use them all anyway + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(decoys_resp.outs[0].outs.size() <= m_required_decoys_count + 1, "for PoS stake tx got greater decoys to mix than requested: " << decoys_resp.outs[0].outs.size() << " < " << m_required_decoys_count + 1); + + auto& ring_candidates = decoys_resp.outs[0].outs; + ring_candidates.emplace_front(td.m_global_output_index, stake_out_target.key); + + std::unordered_set used_gindices; + size_t good_outs_count = 0; + for(auto it = ring_candidates.begin(); it != ring_candidates.end(); ) + { + if (used_gindices.count(it->global_amount_index) != 0) + { + it = ring_candidates.erase(it); + continue; + } + used_gindices.insert(it->global_amount_index); + if (++good_outs_count == m_required_decoys_count + 1) + { + ring_candidates.erase(++it, ring_candidates.end()); + break; + } + ++it; + } + + // won't assert that ring_candidates.size() == m_required_decoys_count + 1 here as we will use all the decoys anyway + if (ring_candidates.size() < m_required_decoys_count + 1) + LOG_PRINT_YELLOW("PoS: using " << ring_candidates.size() - 1 << " decoys for mining tx, while " << m_required_decoys_count << " are required", LOG_LEVEL_1); + + ring_candidates.sort([](auto& l, auto& r){ return l.global_amount_index < r.global_amount_index; }); // sort them now (note absolute_sorted_output_offsets_to_relative_in_place() below) + + uint64_t i = 0; + for(auto& el : ring_candidates) + { + uint64_t gindex = el.global_amount_index; + if (gindex == td.m_global_output_index) + secret_index = i; + ++i; + ring.emplace_back(&el.stealth_address); + stake_input.key_offsets.push_back(el.global_amount_index); + } + r = absolute_sorted_output_offsets_to_relative_in_place(stake_input.key_offsets); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "absolute_sorted_output_offsets_to_relative_in_place failed"); + } + else + { + // no decoys, the ring consist of one element -- the real stake output + ring.emplace_back(&stake_out_target.key); + stake_input.key_offsets.push_back(td.m_global_output_index); + } // sign block actually in coinbase transaction crypto::hash block_hash = currency::get_block_hash(b); - // get stake output pub key (stealth address) for ring signature generation - std::vector keys_ptrs; - keys_ptrs.push_back(&stake_out_target.key); - // generate sring signature - sig.s.resize(1); - crypto::generate_ring_signature(block_hash, stake_input.k_image, keys_ptrs, secret_x, 0, sig.s.data()); + sig.s.resize(ring.size()); + crypto::generate_ring_signature(block_hash, stake_input.k_image, ring, secret_x, secret_index, sig.s.data()); - WLT_LOG_L4("GENERATED RING SIGNATURE for PoS block coinbase: block_id " << block_hash - << "txin.k_image" << stake_input.k_image - << "key_ptr:" << *keys_ptrs[0] - << "signature:" << sig.s); + if (epee::log_space::get_set_log_detalisation_level() >= LOG_LEVEL_4) + { + std::stringstream ss; + ss << "GENERATED RING SIGNATURE for PoS block coinbase:" << ENDL << + " block hash: " << block_hash << ENDL << + " key image: " << stake_input.k_image << ENDL << + " ring:" << ENDL; + for(auto el: ring) + ss << " " << *el << ENDL; + ss << " signature:" << ENDL; + for(auto el: sig.s) + ss << " " << el << ENDL; + WLT_LOG_L4(ss.str()); + } return true; } @@ -4308,7 +4416,7 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address { TIME_MEASURE_START_MS(mining_duration_ms); mining_context ctx = AUTO_VAL_INIT(ctx); - WLT_LOG_L1("Starting PoS mining iteration"); + WLT_LOG_L2("Starting PoS mining iteration"); fill_mining_context(ctx); if (!ctx.is_pos_allowed) @@ -4380,7 +4488,31 @@ bool wallet2::build_minted_block(const mining_context& cxt) { return build_minted_block(cxt, m_account.get_public_address()); } - +//------------------------------------------------------------------ +std::string wallet2::get_extra_text_for_block(uint64_t new_block_expected_height) +{ + size_t entries_voted = 0; + std::string extra_text = "{"; + for (const auto& e : m_votes_config.entries) + { + if (e.h_start <= new_block_expected_height && e.h_end >= new_block_expected_height) + { + //do vote for/against this + if (entries_voted != 0) + extra_text += ","; + extra_text += "\""; + extra_text += e.proposal_id; + extra_text += "\":"; + extra_text += e.vote ? "1" : "0"; + entries_voted++; + } + } + extra_text += "}"; + if (!entries_voted) + extra_text = ""; + return extra_text; +} +//------------------------------------------------------------------ bool wallet2::build_minted_block(const mining_context& cxt, const currency::account_public_address& miner_address) { //found a block, construct it, sign and push to daemon @@ -4394,7 +4526,7 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco tmpl_req.wallet_address = get_account_address_as_str(miner_address); tmpl_req.stakeholder_address = get_account_address_as_str(m_account.get_public_address()); tmpl_req.pos_block = true; - tmpl_req.extra_text = m_miner_text_info; + tmpl_req.extra_text = get_extra_text_for_block(m_chain.get_top_block_height()); tmpl_req.pe = AUTO_VAL_INIT(tmpl_req.pe); tmpl_req.pe.amount = td.amount(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2b782d1e..52471f95 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -392,6 +392,7 @@ namespace tools bool set_core_proxy(const std::shared_ptr& proxy); void set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs); // don't create UTXO defrag. tx if there are less than 'min_outs' outs; don't put more than 'max_outs' outs void set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count); + void set_pos_required_decoys_count(size_t v) { m_required_decoys_count = v; } void set_minimum_height(uint64_t h); std::shared_ptr get_core_proxy(); uint64_t balance() const; @@ -591,6 +592,7 @@ namespace tools bool build_minted_block(const mining_context& cxt); bool build_minted_block(const mining_context& cxt, const currency::account_public_address& miner_address); + std::string get_extra_text_for_block(uint64_t new_block_expected_height); bool reset_history(); bool is_transfer_unlocked(const transfer_details& td) const; bool is_transfer_unlocked(const transfer_details& td, bool for_pos_mining, uint64_t& stake_lock_time) const; @@ -648,6 +650,8 @@ namespace tools bool load_whitelisted_tokens_if_not_loaded() const; bool load_whitelisted_tokens() const; + void set_connectivity_options(unsigned int timeout); + /* 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 @@ -659,6 +663,9 @@ namespace tools void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin); bool check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin, crypto::hash& redeem_tx_id); + void set_votes_config_path(const std::string& path_to_config_file); + const tools::wallet_public::wallet_vote_config& get_current_votes() { return m_votes_config; } + // ionic swaps: bool create_ionic_swap_proposal(const wallet_public::ionic_swap_proposal_info& proposal_details, const currency::account_public_address& destination_addr, wallet_public::ionic_swap_proposal& proposal); bool build_ionic_swap_template(const wallet_public::ionic_swap_proposal_info& proposal_detais, const currency::account_public_address& destination_addr, @@ -685,6 +692,7 @@ namespace tools protected: epee::misc_utils::events_dispatcher m_debug_events_dispatcher; + private: // -------- t_transport_state_notifier ------------------------------------------------ @@ -765,6 +773,7 @@ private: uint64_t get_current_tx_version(); void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const wallet_public::wallet_transfer_info& wti) const; void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const std::string& reason = "internal intention") const; + void load_votes_config(); bool is_need_to_split_outputs(); template bool process_input_t(const input_t& in_t, wallet2::process_transaction_context& ptc, const currency::transaction& tx); @@ -860,6 +869,7 @@ private: uint64_t m_min_utxo_count_for_defragmentation_tx; uint64_t m_max_utxo_count_for_defragmentation_tx; size_t m_decoys_count_for_defragmentation_tx; + size_t m_required_decoys_count; pending_ki_file_container_t m_pending_key_images_file_container; uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value @@ -879,6 +889,10 @@ private: bool m_disable_tor_relay; bool m_use_assets_whitelisting = true; mutable current_operation_context m_current_context; + + std::string m_votes_config_path; + tools::wallet_public::wallet_vote_config m_votes_config; + //this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions friend class test_generator; }; // class wallet2 @@ -906,6 +920,38 @@ namespace boost // } + /*template + inline void serialize(Archive& a, tools::wallet_public::wallet_transfer_info_details& x, const boost::serialization::version_type ver) + { + a & x.rcv; + a & x.spn; + } + + template + inline void serialize(Archive& a, tools::wallet_public::wallet_transfer_info& x, const boost::serialization::version_type ver) + { + + a & x.amount; + a & x.timestamp; + a & x.tx_hash; + a & x.height; + a & x.tx_blob_size; + a & x.payment_id; + a & x.remote_addresses; + a & x.is_income; + a & x.td; + a & x.tx; + a & x.remote_aliases; + a & x.comment; + a & x.contract; + a & x.selected_indicies; + a & x.marketplace_entries; + a & x.unlock_time; + if (ver < 10) + return; + a & x.service_entries; + }*/ + template inline void serialize(Archive& a, tools::wallet_public::escrow_contract_details_basic& x, const boost::serialization::version_type ver) { diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 9658dca3..9967a13c 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -1308,6 +1308,30 @@ namespace wallet_public }; + struct wallet_vote_config_entry + { + std::string proposal_id; + uint64_t h_start; + uint64_t h_end; + bool vote; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(proposal_id) + KV_SERIALIZE(h_start) + KV_SERIALIZE(h_end) + KV_SERIALIZE(vote) + END_KV_SERIALIZE_MAP() + + }; + + struct wallet_vote_config + { + std::vector entries; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(entries) + END_KV_SERIALIZE_MAP() + }; struct asset_funds { diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index ec3d3a00..84b5cb94 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -94,6 +94,8 @@ namespace tools static const uint64_t wallet_rpc_idle_work_period_ms = 2000; m_do_mint = do_mint; + if (m_do_mint) + LOG_PRINT_CYAN("PoS mining is ON", LOG_LEVEL_0); if (!offline_mode) { @@ -171,6 +173,7 @@ namespace tools { w.get_wallet()->set_miner_text_info(command_line::get_arg(vm, arg_miner_text_info)); } + return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 76d4b70f..f6bd872b 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -90,61 +90,61 @@ namespace tools bool 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); BEGIN_URI_MAP2_VIRTUAL() - BEGIN_JSON_RPC_MAP("/json_rpc") - MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_public::COMMAND_RPC_GET_BALANCE) - MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_public::COMMAND_RPC_GET_ADDRESS) - MAP_JON_RPC_WE("get_wallet_info", on_getwallet_info, wallet_public::COMMAND_RPC_GET_WALLET_INFO) - MAP_JON_RPC_WE("get_recent_txs_and_info", on_get_recent_txs_and_info, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO) - MAP_JON_RPC_WE("transfer", on_transfer, wallet_public::COMMAND_RPC_TRANSFER) - MAP_JON_RPC_WE("store", on_store, wallet_public::COMMAND_RPC_STORE) - MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_public::COMMAND_RPC_GET_PAYMENTS) - MAP_JON_RPC_WE("get_bulk_payments", on_get_bulk_payments, wallet_public::COMMAND_RPC_GET_BULK_PAYMENTS) - MAP_JON_RPC_WE("make_integrated_address", on_make_integrated_address, wallet_public::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS) - MAP_JON_RPC_WE("split_integrated_address", on_split_integrated_address, wallet_public::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS) - MAP_JON_RPC_WE("sweep_below", on_sweep_below, wallet_public::COMMAND_SWEEP_BELOW) - MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER) - MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER) - MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS) - MAP_JON_RPC_WE("get_restore_info", on_getwallet_restore_info, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO) - MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO) - MAP_JON_RPC_WE("get_mining_history", on_get_mining_history, wallet_public::COMMAND_RPC_GET_MINING_HISTORY) - MAP_JON_RPC_WE("register_alias", on_register_alias, wallet_public::COMMAND_RPC_REGISTER_ALIAS) - //contracts API - MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL) - MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL) - MAP_JON_RPC_WE("contracts_get_all", on_contracts_get_all, wallet_public::COMMAND_CONTRACTS_GET_ALL) - MAP_JON_RPC_WE("contracts_release", on_contracts_release, wallet_public::COMMAND_CONTRACTS_RELEASE) - MAP_JON_RPC_WE("contracts_request_cancel", on_contracts_request_cancel, wallet_public::COMMAND_CONTRACTS_REQUEST_CANCEL) - MAP_JON_RPC_WE("contracts_accept_cancel", on_contracts_accept_cancel, wallet_public::COMMAND_CONTRACTS_ACCEPT_CANCEL) - //marketplace API - MAP_JON_RPC_WE("marketplace_get_offers_ex", on_marketplace_get_my_offers, wallet_public::COMMAND_MARKETPLACE_GET_MY_OFFERS) - MAP_JON_RPC_WE("marketplace_push_offer", on_marketplace_push_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_OFFER) - MAP_JON_RPC_WE("marketplace_push_update_offer", on_marketplace_push_update_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_UPDATE_OFFER) - MAP_JON_RPC_WE("marketplace_cancel_offer", on_marketplace_cancel_offer, wallet_public::COMMAND_MARKETPLACE_CANCEL_OFFER) - //HTLC API - MAP_JON_RPC_WE("atomics_create_htlc_proposal", on_create_htlc_proposal, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL) - MAP_JON_RPC_WE("atomics_get_list_of_active_htlc", on_get_list_of_active_htlc, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC) - MAP_JON_RPC_WE("atomics_redeem_htlc", on_redeem_htlc, wallet_public::COMMAND_REDEEM_HTLC) - MAP_JON_RPC_WE("atomics_check_htlc_redeemed", on_check_htlc_redeemed, wallet_public::COMMAND_CHECK_HTLC_REDEEMED) + BEGIN_JSON_RPC_MAP("/json_rpc") + MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_public::COMMAND_RPC_GET_BALANCE) + MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_public::COMMAND_RPC_GET_ADDRESS) + MAP_JON_RPC_WE("get_wallet_info", on_getwallet_info, wallet_public::COMMAND_RPC_GET_WALLET_INFO) + MAP_JON_RPC_WE("get_recent_txs_and_info", on_get_recent_txs_and_info, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO) + MAP_JON_RPC_WE("transfer", on_transfer, wallet_public::COMMAND_RPC_TRANSFER) + MAP_JON_RPC_WE("store", on_store, wallet_public::COMMAND_RPC_STORE) + MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_public::COMMAND_RPC_GET_PAYMENTS) + MAP_JON_RPC_WE("get_bulk_payments", on_get_bulk_payments, wallet_public::COMMAND_RPC_GET_BULK_PAYMENTS) + MAP_JON_RPC_WE("make_integrated_address", on_make_integrated_address, wallet_public::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS) + MAP_JON_RPC_WE("split_integrated_address", on_split_integrated_address, wallet_public::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS) + MAP_JON_RPC_WE("sweep_below", on_sweep_below, wallet_public::COMMAND_SWEEP_BELOW) + MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER) + MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER) + MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS) + MAP_JON_RPC_WE("get_restore_info", on_getwallet_restore_info, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO) + MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO) + MAP_JON_RPC_WE("get_mining_history", on_get_mining_history, wallet_public::COMMAND_RPC_GET_MINING_HISTORY) + MAP_JON_RPC_WE("register_alias", on_register_alias, wallet_public::COMMAND_RPC_REGISTER_ALIAS) + //contracts API + MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL) + MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL) + MAP_JON_RPC_WE("contracts_get_all", on_contracts_get_all, wallet_public::COMMAND_CONTRACTS_GET_ALL) + MAP_JON_RPC_WE("contracts_release", on_contracts_release, wallet_public::COMMAND_CONTRACTS_RELEASE) + MAP_JON_RPC_WE("contracts_request_cancel", on_contracts_request_cancel, wallet_public::COMMAND_CONTRACTS_REQUEST_CANCEL) + MAP_JON_RPC_WE("contracts_accept_cancel", on_contracts_accept_cancel, wallet_public::COMMAND_CONTRACTS_ACCEPT_CANCEL) + //marketplace API + MAP_JON_RPC_WE("marketplace_get_offers_ex", on_marketplace_get_my_offers, wallet_public::COMMAND_MARKETPLACE_GET_MY_OFFERS) + MAP_JON_RPC_WE("marketplace_push_offer", on_marketplace_push_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_OFFER) + MAP_JON_RPC_WE("marketplace_push_update_offer", on_marketplace_push_update_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_UPDATE_OFFER) + MAP_JON_RPC_WE("marketplace_cancel_offer", on_marketplace_cancel_offer, wallet_public::COMMAND_MARKETPLACE_CANCEL_OFFER) + //HTLC API + MAP_JON_RPC_WE("atomics_create_htlc_proposal", on_create_htlc_proposal, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL) + MAP_JON_RPC_WE("atomics_get_list_of_active_htlc", on_get_list_of_active_htlc, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC) + MAP_JON_RPC_WE("atomics_redeem_htlc", on_redeem_htlc, wallet_public::COMMAND_REDEEM_HTLC) + MAP_JON_RPC_WE("atomics_check_htlc_redeemed", on_check_htlc_redeemed, wallet_public::COMMAND_CHECK_HTLC_REDEEMED) - //IONIC_SWAPS API - MAP_JON_RPC_WE("ionic_swap_generate_proposal", on_ionic_swap_generate_proposal, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL) - MAP_JON_RPC_WE("ionic_swap_get_proposal_info", on_ionic_swap_get_proposal_info, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO) - MAP_JON_RPC_WE("ionic_swap_accept_proposal", on_ionic_swap_accept_proposal, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL) + //IONIC_SWAPS API + MAP_JON_RPC_WE("ionic_swap_generate_proposal", on_ionic_swap_generate_proposal, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL) + MAP_JON_RPC_WE("ionic_swap_get_proposal_info", on_ionic_swap_get_proposal_info, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO) + MAP_JON_RPC_WE("ionic_swap_accept_proposal", on_ionic_swap_accept_proposal, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL) - //MULTIWALLET APIs - MAP_JON_RPC_WE("mw_get_wallets", on_mw_get_wallets, wallet_public::COMMAND_MW_GET_WALLETS) - MAP_JON_RPC_WE("mw_select_wallet", on_mw_select_wallet, wallet_public::COMMAND_MW_SELECT_WALLET) + //MULTIWALLET APIs + MAP_JON_RPC_WE("mw_get_wallets", on_mw_get_wallets, wallet_public::COMMAND_MW_GET_WALLETS) + MAP_JON_RPC_WE("mw_select_wallet", on_mw_select_wallet, wallet_public::COMMAND_MW_SELECT_WALLET) - //basic crypto operations - MAP_JON_RPC_WE("sign_message", on_sign_message, wallet_public::COMMAND_SIGN_MESSAGE) - MAP_JON_RPC_WE("encrypt_data", on_encrypt_data, wallet_public::COMMAND_ENCRYPT_DATA) - MAP_JON_RPC_WE("decrypt_data", on_decrypt_data, wallet_public::COMMAND_DECRYPT_DATA) + //basic crypto operations + MAP_JON_RPC_WE("sign_message", on_sign_message, wallet_public::COMMAND_SIGN_MESSAGE) + MAP_JON_RPC_WE("encrypt_data", on_encrypt_data, wallet_public::COMMAND_ENCRYPT_DATA) + MAP_JON_RPC_WE("decrypt_data", on_decrypt_data, wallet_public::COMMAND_DECRYPT_DATA) END_JSON_RPC_MAP() END_URI_MAP2() - //json_rpc - bool on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx); + //json_rpc + bool on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_getaddress(const wallet_public::COMMAND_RPC_GET_ADDRESS::request& req, wallet_public::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_getwallet_info(const wallet_public::COMMAND_RPC_GET_WALLET_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx); @@ -162,8 +162,8 @@ namespace tools bool on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_register_alias(const wallet_public::COMMAND_RPC_REGISTER_ALIAS::request& req, wallet_public::COMMAND_RPC_REGISTER_ALIAS::response& res, epee::json_rpc::error& er, connection_context& cntx); - - + + bool on_contracts_send_proposal(const wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL::request& req, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_contracts_accept_proposal(const wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL::request& req, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_contracts_get_all(const wallet_public::COMMAND_CONTRACTS_GET_ALL::request& req, wallet_public::COMMAND_CONTRACTS_GET_ALL::response& res, epee::json_rpc::error& er, connection_context& cntx); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 67a99557..ec5e1edf 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1037,6 +1037,9 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st LOG_ERROR("Unexpected location reached"); #endif } + + w->set_votes_config_path(m_data_dir + "/" + CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME); + std::string return_code = API_RETURN_CODE_OK; while (true) @@ -1051,6 +1054,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st //w->get_unconfirmed_transfers(owr.recent_history.unconfirmed); w->get_unconfirmed_transfers(owr.recent_history.history, exclude_mining_txs); owr.wallet_local_bc_size = w->get_blockchain_current_size(); + //workaround for missed fee //owr.seed = w->get_account().get_seed_phrase(); break; @@ -1142,6 +1146,7 @@ std::string wallets_manager::generate_wallet(const std::wstring& path, const std { std::shared_ptr w(new tools::wallet2()); w->set_use_deffered_global_outputs(m_use_deffered_global_outputs); + w->set_votes_config_path(m_data_dir + "/" + CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME); owr.wallet_id = m_wallet_id_counter++; w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); if (m_remote_node_mode) @@ -1248,6 +1253,7 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std: { std::shared_ptr w(new tools::wallet2()); w->set_use_deffered_global_outputs(m_use_deffered_global_outputs); + w->set_votes_config_path(m_data_dir + "/" + CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME); owr.wallet_id = m_wallet_id_counter++; w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); if (m_remote_node_mode) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 183cc861..4ff2b66d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(coretests rpc wallet currency_core common crypto zlibstati target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(hash-tests crypto ethash) target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(performance_tests currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(performance_tests wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(unit_tests wallet currency_core common crypto gtest_main zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_clt currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_srv currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index fab87508..a158e044 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -516,6 +516,8 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain, wallets.back().wallet->assign_account(a); wallets.back().wallet->get_account().set_createtime(0); wallets.back().wallet->set_core_proxy(tmp_proxy); + wallets.back().wallet->set_minimum_height(0); + wallets.back().wallet->set_pos_required_decoys_count(0); currency::core_runtime_config pc = cc; pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 67a87489..bd62a042 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1104,6 +1104,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(pos_wallet_big_block_test); //GENERATE_AND_PLAY(block_template_against_txs_size); // Long test! by demand only GENERATE_AND_PLAY(pos_altblocks_validation); + GENERATE_AND_PLAY(pos_mining_with_decoys); // alternative blocks and generic chain-switching tests GENERATE_AND_PLAY(gen_chain_switch_pow_pos); diff --git a/tests/core_tests/pos_basic_tests.cpp b/tests/core_tests/pos_basic_tests.cpp index 22b40f78..f27d2dfb 100644 --- a/tests/core_tests/pos_basic_tests.cpp +++ b/tests/core_tests/pos_basic_tests.cpp @@ -139,3 +139,121 @@ bool gen_pos_basic_tests::check_exchange_1(currency::core& c, size_t ev_index, c CHECK_EQ(offers.size(), 1); return true; } + + +//------------------------------------------------------------------------------ + +pos_mining_with_decoys::pos_mining_with_decoys() +{ + REGISTER_CALLBACK_METHOD(pos_mining_with_decoys, c1); +} + +bool pos_mining_with_decoys::generate(std::vector& events) const +{ + uint64_t ts = test_core_time::get_time(); + m_accounts.resize(TOTAL_ACCS_COUNT); + currency::account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); + currency::account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts); + currency::account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts); + currency::account_base& carol_acc = m_accounts[CAROL_ACC_IDX]; carol_acc.generate(); carol_acc.set_createtime(ts); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); + DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); + + bool r = false; + std::vector sources; + r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), 2 * COIN, 0); + CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); + std::vector destinations; + destinations.emplace_back(47 * TESTS_DEFAULT_FEE, alice_acc.get_public_address()); + destinations.emplace_back(47 * TESTS_DEFAULT_FEE, miner_acc.get_public_address()); // as a decoy for Alice + destinations.emplace_back(5 * TESTS_DEFAULT_FEE, bob_acc.get_public_address()); + destinations.emplace_back(COIN, carol_acc.get_public_address()); + + transaction tx_0{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + events.push_back(tx_0); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); + + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool pos_mining_with_decoys::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false; + CHECK_AND_ASSERT_MES(!c.get_blockchain_storage().get_core_runtime_config().is_hardfork_active_for_height(4, c.get_top_block_height()), false, "HF4 should not be active"); + + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); + miner_wlt->refresh(); + + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); + alice_wlt->refresh(); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", 47 * TESTS_DEFAULT_FEE, INVALID_BALANCE_VAL, 47 * TESTS_DEFAULT_FEE), false, ""); + + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); + bob_wlt->refresh(); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", 5 * TESTS_DEFAULT_FEE, INVALID_BALANCE_VAL, 5 * TESTS_DEFAULT_FEE), false, ""); + + std::shared_ptr carol_wlt = init_playtime_test_wallet(events, c, m_accounts[CAROL_ACC_IDX]); + carol_wlt->refresh(); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*carol_wlt, "Carol", COIN, INVALID_BALANCE_VAL, COIN), false, ""); + + + // 1. Alice should be able to mine a PoS block with 1 decoys (ring size == 2) + size_t top_block_height = c.get_top_block_height(); + + r = alice_wlt->try_mint_pos(m_accounts[ALICE_ACC_IDX].get_public_address()); + CHECK_AND_ASSERT_MES(r, false, "try_mint_pos failed"); + + { + block b{}; + CHECK_AND_ASSERT_MES(c.get_blockchain_storage().get_top_block(b), false, ""); + CHECK_AND_ASSERT_MES(get_block_height(b) == top_block_height + 1, false, "unexpected top block height"); + + txin_to_key& intk = boost::get(b.miner_tx.vin[1]); + CHECK_AND_ASSERT_MES(intk.amount == 47 * TESTS_DEFAULT_FEE, false, "incorrect amount: " << intk.amount); + CHECK_AND_ASSERT_MES(intk.key_offsets.size() == 2, false, "unexpected ring size: " << intk.key_offsets.size()); + } + + + // 2. Bob should only be able to mine a PoS block with zero decoys (ring size == 1) + top_block_height = c.get_top_block_height(); + + r = bob_wlt->try_mint_pos(m_accounts[BOB_ACC_IDX].get_public_address()); + CHECK_AND_ASSERT_MES(r, false, "try_mint_pos failed"); + + { + block b{}; + CHECK_AND_ASSERT_MES(c.get_blockchain_storage().get_top_block(b), false, ""); + CHECK_AND_ASSERT_MES(get_block_height(b) == top_block_height + 1, false, "unexpected top block height"); + + txin_to_key& intk = boost::get(b.miner_tx.vin[1]); + CHECK_AND_ASSERT_MES(intk.amount == 5 * TESTS_DEFAULT_FEE, false, "incorrect amount: " << intk.amount); + CHECK_AND_ASSERT_MES(intk.key_offsets.size() == 1, false, "unexpected ring size: " << intk.key_offsets.size()); + } + + + // 3. Carol should only be able to mine a PoS block with CURRENCY_DEFAULT_DECOY_SET_SIZE decoys (ring size == CURRENCY_DEFAULT_DECOY_SET_SIZE + 1) + top_block_height = c.get_top_block_height(); + + r = carol_wlt->try_mint_pos(m_accounts[CAROL_ACC_IDX].get_public_address()); + CHECK_AND_ASSERT_MES(r, false, "try_mint_pos failed"); + + { + block b{}; + CHECK_AND_ASSERT_MES(c.get_blockchain_storage().get_top_block(b), false, ""); + CHECK_AND_ASSERT_MES(get_block_height(b) == top_block_height + 1, false, "unexpected top block height"); + + txin_to_key& intk = boost::get(b.miner_tx.vin[1]); + CHECK_AND_ASSERT_MES(intk.amount == COIN, false, "incorrect amount: " << intk.amount); + CHECK_AND_ASSERT_MES(intk.key_offsets.size() == CURRENCY_DEFAULT_DECOY_SET_SIZE + 1, false, "unexpected ring size: " << intk.key_offsets.size()); + } + + return true; +} diff --git a/tests/core_tests/pos_basic_tests.h b/tests/core_tests/pos_basic_tests.h index 6bdb5c45..bd4fbf10 100644 --- a/tests/core_tests/pos_basic_tests.h +++ b/tests/core_tests/pos_basic_tests.h @@ -5,6 +5,7 @@ #pragma once #include "chaingen.h" +#include "wallet_tests_basic.h" struct gen_pos_basic_tests : public test_chain_unit_base { @@ -22,3 +23,12 @@ struct gen_pos_basic_tests : public test_chain_unit_base bool check_exchange_1(currency::core& c, size_t ev_index, const std::vector& events); }; + + +struct pos_mining_with_decoys : public wallet_test +{ + pos_mining_with_decoys(); + bool generate(std::vector& events) const; + bool configure_core(currency::core& c, size_t ev_index, const std::vector& events); + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; diff --git a/tests/performance_tests/api_test.cpp b/tests/performance_tests/api_test.cpp new file mode 100644 index 00000000..6a492c28 --- /dev/null +++ b/tests/performance_tests/api_test.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "wallet/core_rpc_proxy.h" +#include "wallet/core_default_rpc_proxy.h" + +int test_get_rand_outs() +{ + currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response rsp = AUTO_VAL_INIT(rsp); + req.use_forced_mix_outs = false; + req.outs_count = 10 + 1; + for (size_t i = 0; i != 50; i++) + req.amounts.push_back(COIN); + + std::shared_ptr m_core_proxy(new tools::default_http_core_proxy()); + m_core_proxy->set_connection_addr("127.0.0.1:11211"); + m_core_proxy->check_connection(); + + bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rsp); + + return 0; +} diff --git a/tests/unit_tests/votes_tests.cpp b/tests/unit_tests/votes_tests.cpp new file mode 100644 index 00000000..d6f0a90c --- /dev/null +++ b/tests/unit_tests/votes_tests.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2012-2014 The Zano developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gtest/gtest.h" + +#include +#include + +#include "misc_language.h" +#include "currency_core/currency_format_utils.h" + + +TEST(governance_testig, governance_tests_1) +{ + std::string vote = "{\"ZGP11\":1,\"ZGP23\":0}"; + + std::list> votes; + currency::parse_vote(vote, votes); + ASSERT_TRUE(votes.size() == 2); + ASSERT_TRUE(votes.begin()->first == "ZGP11"); + ASSERT_TRUE(votes.begin()->second == true); + ASSERT_TRUE((++votes.begin())->first == "ZGP23"); + ASSERT_TRUE((++votes.begin())->second == false); + +} \ No newline at end of file