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/boost_serialization_maps.h b/src/common/boost_serialization_maps.h index 805febee..7f44e4d2 100644 --- a/src/common/boost_serialization_maps.h +++ b/src/common/boost_serialization_maps.h @@ -18,6 +18,7 @@ template struct TAssertEquality { #define BOOST_SERIALIZE(x) _arch & x; +#define BOOST_SERIALIZE_BASE_CLASS(class_type) _arch & static_cast(*this); #define BOOST_END_VERSION_UNDER(x) \ if(ver < x ) {return;} 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..9ccee98b 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; @@ -4201,9 +4246,6 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const if (need_to_profile && max_mixins_count > 0) { m_performance_data.tx_mixin_count.push(max_mixins_count); -#ifdef _DEBUG - LOG_PRINT_L0("[TX_MIXINS]: " << max_mixins_count); -#endif } //check if there is already transaction with this hash @@ -5660,15 +5702,19 @@ bool blockchain_storage::validate_pos_block(const block& b, CHECK_AND_ASSERT_MES(!have_tx_keyimg_as_spent(stake_key_image), false, "stake key image has been already spent in blockchain: " << stake_key_image); } - // the following check is de-facto not applicable since 2021-10, but left intact to avoid consensus issues - // PoS blocks don't use etc_tx_time anymore to store actual timestamp; instead, they use tx_service_attachment in mining tx extra - uint64_t actual_ts = get_actual_timestamp(b); - if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) || - (actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) - ) + if (!is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) { - LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAX_ACTUAL_TIMESTAMP_TO_MINED << " s."); - return false; + // the following check is de-facto not applicable since 2021-10, but left intact to avoid consensus issues + // PoS blocks don't use etc_tx_time anymore to store actual timestamp; instead, they use tx_service_attachment in mining tx extra + // TODO: remove this entire section after HF4 -- sowle + uint64_t actual_ts = get_block_timestamp_from_miner_tx_extra(b); + if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) || + (actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) + ) + { + LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAX_ACTUAL_TIMESTAMP_TO_MINED << " s."); + return false; + } } // build kernel and calculate hash 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 3a48cf8c..e291cc02 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 @@ -246,8 +249,8 @@ #define WALLET_FILE_SERIALIZATION_VERSION 160 #define WALLET_FILE_LAST_SUPPORTED_VERSION 160 #else -#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+74) -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+74) +#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76) #endif #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) 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..0ff7c36f 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)) @@ -3367,9 +3396,8 @@ namespace currency return median_fee * 10; } //--------------------------------------------------------------- - // NOTE: this function is obsolete and depricated - [[deprecated("PoS block real timestamp is set using a service attachment in mining tx extra since 2021-10")]] - uint64_t get_actual_timestamp(const block& b) + // TODO: remove this function after HF4 -- sowle + uint64_t get_block_timestamp_from_miner_tx_extra(const block& b) { uint64_t tes_ts = b.timestamp; if (is_pos_block(b)) @@ -3658,50 +3686,6 @@ namespace currency boost::get(res[i]) += boost::get(res[i - 1]); } - return res; - } - //--------------------------------------------------------------- - // DEPRECATED: consider using prepare_outputs_entries_for_key_offsets and absolute_sorted_output_offsets_to_relative_in_place instead - std::vector absolute_output_offsets_to_relative(const std::vector& off) - { - std::vector res = off; - if (off.size() < 2) - return res; - - std::sort(res.begin(), res.end(), [](const txout_ref_v& lft, const txout_ref_v& rght) - { - if (lft.type() == typeid(uint64_t)) - { - if (rght.type() == typeid(uint64_t)) - return boost::get(lft) < boost::get(rght); - else if (rght.type() == typeid(ref_by_id)) - return true; - else - LOG_ERROR("Unknown type in txout_v"); - } - else if (lft.type() == typeid(ref_by_id)) - { - if (rght.type() == typeid(uint64_t)) - return false; - else if (rght.type() == typeid(ref_by_id)) - return false; // don't change the order of ref_by_id elements - else - LOG_ERROR("Unknown type in txout_v"); - } - return false; - });//just to be sure, actually it is already should be sorted - - //find starter index - skip ref_by_id entries - size_t i = res.size() - 1; - while (i != 0 && res[i].type() == typeid(ref_by_id)) - --i; - - for (; i != 0; i--) - { - boost::get(res[i]) -= boost::get(res[i - 1]); - } - - return res; } //--------------------------------------------------------------- @@ -3801,33 +3785,6 @@ namespace currency } return sum_of_amount_commitments == amount * native_coin_asset_id_pt; } - //--------------------------------------------------------------- - // DEPRECATED, don't use -- sowle - uint64_t get_amount_for_zero_pubkeys(const transaction& tx) - { - uint64_t found_alias_reward = 0; - for (const auto& out : tx.vout) - { - VARIANT_SWITCH_BEGIN(out); - VARIANT_CASE_CONST(tx_out_bare, out) - if (out.target.type() != typeid(txout_to_key)) - continue; - - const txout_to_key& o = boost::get(out.target); - if (o.key == null_pkey) - found_alias_reward += out.amount; - VARIANT_CASE_CONST(tx_out_zarcanum, o) - //@#@ - VARIANT_SWITCH_END(); - } -#ifdef TESTNET - found_alias_reward = 10 * COIN; -#else - @#@ fix it for mainnet bui -#endif - return found_alias_reward; - } - //--------------------------------------------------------------- bool get_aliases_reward_account(account_public_address& acc) { @@ -3881,7 +3838,11 @@ namespace currency VARIANT_SWITCH_END(); } VARIANT_CASE_CONST(tx_out_zarcanum, o) - //@#@ + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.stealth_address)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.concealing_point)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.amount_commitment)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.blinded_asset_id)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.encrypted_amount)); VARIANT_SWITCH_END(); ++i; } diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 5baad2aa..96cb7c3b 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -405,15 +405,13 @@ namespace currency uint64_t get_block_height(const transaction& coinbase); uint64_t get_block_height(const block& b); std::vector relative_output_offsets_to_absolute(const std::vector& off); - // DEPRECATED: consider using prepare_outputs_entries_for_key_offsets and absolute_sorted_output_offsets_to_relative_in_place instead - [[deprecated]] std::vector absolute_output_offsets_to_relative(const std::vector& off); bool absolute_sorted_output_offsets_to_relative_in_place(std::vector& offsets) noexcept; // prints amount in format "3.14", "0.0" std::string print_money_brief(uint64_t amount, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT); - uint64_t get_actual_timestamp(const block& b); // obsolete and depricated, use get_block_datetime + uint64_t get_block_timestamp_from_miner_tx_extra(const block& b); // remove this function after HF4 -- sowle uint64_t get_block_datetime(const block& b); void set_block_datetime(uint64_t datetime, block& b); @@ -425,8 +423,6 @@ namespace currency bool does_tx_have_only_mixin_inputs(const transaction& tx); bool is_showing_sender_addres(const transaction& tx); bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt = nullptr); - [[deprecated("Use check_native_coins_amount_burnt_in_outs instead")]] uint64_t get_amount_for_zero_pubkeys(const transaction& tx); - //std::string get_comment_from_tx(const transaction& tx); std::string print_stake_kernel_info(const stake_kernel& sk); std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector& output_keys_ptrs, const std::vector& sig); @@ -446,7 +442,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/currency_core/currency_format_utils_transactions.cpp b/src/currency_core/currency_format_utils_transactions.cpp index d4650dfa..d29fab6a 100644 --- a/src/currency_core/currency_format_utils_transactions.cpp +++ b/src/currency_core/currency_format_utils_transactions.cpp @@ -408,4 +408,17 @@ namespace currency #endif } + //---------------------------------------------------------------------------------------------------- + std::string transform_tx_to_str(const currency::transaction& tx) + { + return currency::obj_to_json_str(tx); + } + //---------------------------------------------------------------------------------------------------- + transaction transform_str_to_tx(const std::string& tx_str) + { + CHECK_AND_ASSERT_THROW_MES(false, "transform_str_to_tx shoruld never be called"); + return transaction(); + } + + } \ No newline at end of file diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index 087e19be..2fc8beaf 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -329,5 +329,9 @@ namespace currency }; // struct tx_generation_context bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key); + std::string transform_tx_to_str(const transaction& tx); + transaction transform_str_to_tx(const std::string& tx_str); + + } // namespace currency diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index f7d1a92e..ea512b08 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit f7d1a92e9d3b2126cca41f589260802346b29a17 +Subproject commit ea512b08c9166406ae5fd84ae69a6b57c9a03b67 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..b1e296fb 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,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) + MAP_JON_RPC ("getrandom_outs", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) + 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 d26d0849..4da5fb2a 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::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; } //---------------------------------------------------------------------------------------------------- @@ -1087,7 +1200,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector& args } } - tools::wallet2::transfer_container transfers; + tools::transfer_container transfers; m_wallet->get_transfers(transfers); bool transfers_found = false; @@ -1130,7 +1243,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector& args bool simple_wallet::show_incoming_transfers_counts(const std::vector& args) { - tools::wallet2::transfer_container transfers; + tools::transfer_container transfers; m_wallet->get_transfers(transfers); uint64_t spent_count = 0; @@ -1189,7 +1302,7 @@ bool simple_wallet::fix_collisions(const std::vector &args) return true; } -void print_td_list(const std::list& td) +void print_td_list(const std::list& td) { message_writer() << "entries found: " << td.size(); for (auto& e : td) @@ -1208,7 +1321,7 @@ bool simple_wallet::scan_transfers_for_id(const std::vector &args) fail_msg_writer() << "expected valid tx id"; return true; } - std::list td; + std::list td; m_wallet->scan_for_transaction_entries(id, currency::null_ki, td); print_td_list(td); return true; @@ -1222,7 +1335,7 @@ bool simple_wallet::scan_transfers_for_ki(const std::vector &args) fail_msg_writer() << "expected valid key_image"; return true; } - std::list td; + std::list td; m_wallet->scan_for_transaction_entries(currency::null_hash, ki, td); print_td_list(td); return true; @@ -1249,7 +1362,7 @@ bool simple_wallet::get_transfer_info(const std::vector &args) } size_t i = 0; - tools::wallet2::transfer_details td = AUTO_VAL_INIT(td); + tools::transfer_details td = AUTO_VAL_INIT(td); if (epee::string_tools::get_xtype_from_string(i, args[0])) { @@ -1294,7 +1407,7 @@ bool simple_wallet::show_payments(const std::vector &args) bool payments_found = false; for(std::string arg : args) { - std::list payments; + std::list payments; m_wallet->get_payments(arg, payments); if (payments.empty()) { @@ -1302,7 +1415,7 @@ bool simple_wallet::show_payments(const std::vector &args) continue; } - for (const tools::wallet2::payment_details& pd : payments) + for (const tools::payment_details& pd : payments) { if (!payments_found) { @@ -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/version.h.in b/src/version.h.in index 40fffc58..28dbd4ae 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 237 +#define PROJECT_VERSION_BUILD_NO 244 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" 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 e805280d..6c1b4c78 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" @@ -66,24 +67,21 @@ namespace tools , m_wcallback(new i_wallet2_callback()) //stub , m_core_proxy(new default_http_core_proxy()) , m_upper_transaction_size_limit(0) - , m_height_of_start_sync(0) - , m_last_sync_percent(0) , m_fake_outputs_count(0) , m_do_rise_transfer(false) , m_log_prefix("???") , m_watch_only(false) - , m_last_pow_block_h(0) - , m_minimum_height(WALLET_MINIMUM_HEIGHT_UNSET_CONST) + , 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) - , m_current_wallet_file_size(0) , m_use_deffered_global_outputs(false) #ifdef DISABLE_TOR , m_disable_tor_relay(true) #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(); } @@ -137,45 +135,25 @@ std::string wallet2::transfer_flags_to_str(uint32_t flags) result[4] = 'c'; return result; } -//---------------------------------------------------------------------------------------------------- -std::string wallet2::transform_tx_to_str(const currency::transaction& tx) -{ - return currency::obj_to_json_str(tx); -} -//---------------------------------------------------------------------------------------------------- -currency::transaction wallet2::transform_str_to_tx(const std::string& tx_str) -{ - THROW_IF_TRUE_WALLET_INT_ERR_EX_NO_HANDLER(false, "transform_str_to_tx shoruld never be called"); - return currency::transaction(); -} -//---------------------------------------------------------------------------------------------------- -uint64_t wallet2::transfer_details_base_to_amount(const transfer_details_base& tdb) -{ - return tdb.amount(); -} -//---------------------------------------------------------------------------------------------------- -std::string wallet2::transfer_details_base_to_tx_hash(const transfer_details_base& tdb) -{ - return epee::string_tools::pod_to_hex(currency::get_transaction_hash(tdb.m_ptx_wallet_info->m_tx)); -} -//---------------------------------------------------------------------------------------------------- -const wallet2::transaction_wallet_info& wallet2::transform_ptr_to_value(const std::shared_ptr& a) -{ - return *a; -} -//---------------------------------------------------------------------------------------------------- -std::shared_ptr wallet2::transform_value_to_ptr(const wallet2::transaction_wallet_info& d) -{ - THROW_IF_TRUE_WALLET_INT_ERR_EX_NO_HANDLER(false, "transform_value_to_ptr shoruld never be called"); - return std::shared_ptr(); -} - //---------------------------------------------------------------------------------------------------- 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) @@ -1248,12 +1226,12 @@ void wallet2::change_contract_state(wallet_public::escrow_contract_details_basic contract.state = new_state; } //----------------------------------------------------------------------------------------------------- -void from_outs_to_received_items(const std::vector& outs, std::vector& received, const currency::transaction& tx) +void from_outs_to_received_items(const std::vector& outs, std::vector& received, const currency::transaction& tx) { for (const auto& item : outs) { if(!out_is_multisig(tx.vout[item.index])) - received.push_back(tools::wallet2::payment_details_subtransfer{ item.asset_id, item.amount}); + received.push_back(tools::payment_details_subtransfer{ item.asset_id, item.amount}); } } //----------------------------------------------------------------------------------------------------- @@ -1772,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()) @@ -2820,29 +2798,9 @@ bool wallet2::clear() //---------------------------------------------------------------------------------------------------- bool wallet2::reset_all() { - //m_blockchain.clear(); - m_chain.clear(); - m_transfers.clear(); - m_amount_gindex_to_transfer_id.clear(); - m_key_images.clear(); - // m_pending_key_images is not cleared intentionally - m_unconfirmed_in_transfers.clear(); - m_unconfirmed_txs.clear(); - m_unconfirmed_multisig_transfers.clear(); - // m_tx_keys is not cleared intentionally, considered to be safe - m_multisig_transfers.clear(); - m_payments.clear(); - m_transfer_history.clear(); - //m_account = AUTO_VAL_INIT(m_account); - - //m_local_bc_size = 1; //including genesis - m_last_bc_timestamp = 0; - m_height_of_start_sync = 0; - m_last_sync_percent = 0; - m_last_pow_block_h = 0; - m_current_wallet_file_size = 0; - m_custom_assets.clear(); - m_own_asset_descriptors.clear(); + //static_cast(*this) = wallet2_base_state{}; + static_cast(*this).~wallet2_base_state(); + new (static_cast(this)) wallet2_base_state(); return true; } //---------------------------------------------------------------------------------------------------- @@ -3054,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(); @@ -3092,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) { @@ -3101,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 { @@ -3122,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) { @@ -3197,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 @@ -3547,8 +3519,6 @@ bool wallet2::load_whitelisted_tokens() const if(!m_use_assets_whitelisting) return true; - - m_whitelisted_assets.clear(); std::string body; wallet_public::assets_whitelist aw = AUTO_VAL_INIT(aw); @@ -3564,14 +3534,17 @@ bool wallet2::load_whitelisted_tokens() const //---------------------------------------------------------------------------------------------------- bool wallet2::load_whitelisted_tokens_if_not_loaded() const { - if (m_whitelisted_assets.size()) + if (m_whitelist_updated) { return true; } - return load_whitelisted_tokens(); + if (!load_whitelisted_tokens()) + return false; + m_whitelist_updated = true; + return true; } //---------------------------------------------------------------------------------------------------- -void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) const +void wallet2::get_transfers(transfer_container& incoming_transfers) const { incoming_transfers = m_transfers; } @@ -3673,7 +3646,7 @@ std::string wallet2::get_balance_str() const return ss.str(); } //---------------------------------------------------------------------------------------------------- -void wallet2::get_payments(const std::string& payment_id, std::list& payments, uint64_t min_height) const +void wallet2::get_payments(const std::string& payment_id, std::list& payments, uint64_t min_height) const { auto range = m_payments.equal_range(payment_id); std::for_each(range.first, range.second, [&payments, &min_height](const payment_container::value_type& x) @@ -3999,7 +3972,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) { @@ -4171,26 +4148,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 && !is_auditable()) + { + 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; } @@ -4215,7 +4266,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful // get decoys outputs and construct miner tx static size_t required_decoys_count = 4; // TODO @#@# set them somewhere else static bool use_only_forced_to_mix = false; // TODO @#@# set them somewhere else - if (required_decoys_count > 0) + if (required_decoys_count > 0 && !is_auditable()) { COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request decoys_req = AUTO_VAL_INIT(decoys_req); decoys_req.height_upper_limit = m_last_pow_block_h; // request decoys to be either older than, or the same age as stake output's height @@ -4366,7 +4417,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) @@ -4438,7 +4489,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 @@ -4452,7 +4527,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(); @@ -4912,10 +4987,10 @@ std::string get_random_rext(size_t len) // local_transfers_struct - structure to avoid copying the whole m_transfers struct local_transfers_struct { - local_transfers_struct(wallet2::transfer_container& tf) :l_transfers_ref(tf) + local_transfers_struct(transfer_container& tf) :l_transfers_ref(tf) {} - wallet2::transfer_container& l_transfers_ref; + transfer_container& l_transfers_ref; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(l_transfers_ref) END_KV_SERIALIZE_MAP() diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 63eb6d0c..0e42bc0b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -45,18 +45,11 @@ #include "tor-connect/torlib/tor_lib_iface.h" #include "currency_core/pos_mining.h" #include "view_iface.h" - +#include "wallet2_base.h" #define WALLET_DEFAULT_TX_SPENDABLE_AGE 10 #define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1 -#define WALLET_TRANSFER_DETAIL_FLAG_SPENT uint32_t(1 << 0) -#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED uint32_t(1 << 1) -#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION uint32_t(1 << 2) -#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3) -#define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing) -#define WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM uint32_t(1 << 5) // for htlc keeps info if this htlc belong as redeem or as refund - const uint64_t WALLET_MINIMUM_HEIGHT_UNSET_CONST = std::numeric_limits::max(); @@ -84,9 +77,6 @@ const uint64_t WALLET_MINIMUM_HEIGHT_UNSET_CONST = std::numeric_limits #define WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, "[W:" << m_log_prefix << "] " << msg) #define WLT_THROW_IF_FALSE_WALLET_EX_MES(cond, exception_t, msg, ...) THROW_IF_FALSE_WALLET_EX_MES(cond, exception_t, "[W:" << m_log_prefix << "] " << msg, ## __VA_ARGS__) - - - class test_generator; namespace tools @@ -124,391 +114,121 @@ namespace tools virtual bool on_mw_select_wallet(uint64_t wallet_id) { return true; } }; - struct tx_dust_policy - { - uint64_t dust_threshold = 0; - bool add_to_fee = false; - currency::account_public_address addr_for_dust; - tx_dust_policy(uint64_t a_dust_threshold = DEFAULT_DUST_THRESHOLD, bool an_add_to_fee = true, currency::account_public_address an_addr_for_dust = currency::account_public_address()) - : dust_threshold(a_dust_threshold) - , add_to_fee(an_add_to_fee) - , addr_for_dust(an_addr_for_dust) - { - } - - BEGIN_SERIALIZE_OBJECT() - FIELD(dust_threshold) - FIELD(add_to_fee) - FIELD(addr_for_dust) - END_SERIALIZE() - }; class test_generator; -#pragma pack(push, 1) - struct out_key_to_ki + + /* + This structure aggregates all variables that hold current wallet synchronization state and could be reset + */ + struct wallet2_base_state { - crypto::public_key out_key; - crypto::key_image key_image; - }; -#pragma pack(pop) + wallet_chain_shortener m_chain; + uint64_t m_minimum_height = WALLET_MINIMUM_HEIGHT_UNSET_CONST; + amount_gindex_to_transfer_id_container m_amount_gindex_to_transfer_id; + transfer_container m_transfers; + multisig_transfer_container m_multisig_transfers; + payment_container m_payments; + std::unordered_map m_key_images; + std::vector m_transfer_history; + std::unordered_map m_unconfirmed_in_transfers; + std::unordered_map m_unconfirmed_txs; + 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 + mutable std::unordered_map m_whitelisted_assets; //assets that whitelisted + escrow_contracts_container m_contracts; + 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 + std::unordered_map m_active_htlcs_txid; // map [txid] -> transfer index, limitation: 1 transactiom -> 1 htlc + std::list m_money_expirations; + std::unordered_map m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key + uint64_t m_last_pow_block_h = 0; + std::list> m_rollback_events; + + //variables that not being serialized + std::atomic m_last_bc_timestamp = 0; + uint64_t m_height_of_start_sync = 0; + std::atomic m_last_sync_percent = 0; + mutable uint64_t m_current_wallet_file_size = 0; - typedef tools::pod_array_file_container pending_ki_file_container_t; - - namespace detail - { - //---------------------------------------------------------------------------------------------------- - inline void digit_split_strategy(const std::vector& dsts, - const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, - std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) + //=============================================================== + template + inline void serialize(t_archive &a, const unsigned int ver) { - splitted_dsts.clear(); - dust = 0; - - for(auto& de : dsts) + if (t_archive::is_saving::value) { - if (de.addr.size() > 1) - { - //for multisig we don't split - splitted_dsts.push_back(de); - } - else if (de.htlc_options.expiration != 0) - { - //for htlc we don't do split - splitted_dsts.push_back(de); - } - else - { - currency::decompose_amount_into_digits(de.amount, dust_threshold, - [&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, de.addr, de.asset_id)); }, - [&](uint64_t a_dust) { splitted_dsts.push_back(currency::tx_destination_entry(a_dust, de.addr, de.asset_id)); }, max_output_allowed); - } + LOG_PRINT_MAGENTA("Serializing file with ver: " << ver, LOG_LEVEL_0); } - if (change_dst.amount > 0) + + // do not load wallet if data version is greather than the code version + if (ver > WALLET_FILE_SERIALIZATION_VERSION) { - if (change_dst.addr.size() > 1) + LOG_PRINT_MAGENTA("Wallet file truncated due to WALLET_FILE_SERIALIZATION_VERSION is more then curren build", LOG_LEVEL_0); + return; + } + if (ver < WALLET_FILE_LAST_SUPPORTED_VERSION) + { + LOG_PRINT_MAGENTA("Wallet file truncated due to ver(" << ver << ") is less then WALLET_FILE_LAST_SUPPORTED_VERSION", LOG_LEVEL_0); + return; + } + + if (t_archive::is_saving::value) + { + uint64_t formation_ver = CURRENCY_FORMATION_VERSION; + a & formation_ver; + } + else + { + uint64_t formation_ver = 0; + a & formation_ver; + if (formation_ver != CURRENCY_FORMATION_VERSION) { - //for multisig we don't split - splitted_dsts.push_back(change_dst); - } - else - { - currency::decompose_amount_into_digits(change_dst.amount, dust_threshold, - [&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, change_dst.addr)); }, - [&](uint64_t a_dust) { dust = a_dust; }, max_output_allowed); + LOG_PRINT_MAGENTA("Wallet file truncated due to mismatch CURRENCY_FORMATION_VERSION", LOG_LEVEL_0); + return; } } + //convert from old version + a & m_chain; + a & m_minimum_height; + a & m_amount_gindex_to_transfer_id; + a & m_transfers; + a & m_multisig_transfers; + a & m_key_images; + a & m_unconfirmed_txs; + a & m_unconfirmed_multisig_transfers; + a & m_payments; + a & m_transfer_history; + a & m_unconfirmed_in_transfers; + a & m_contracts; + a & m_money_expirations; + a & m_pending_key_images; + a & m_tx_keys; + a & m_last_pow_block_h; + a & m_htlcs; + a & m_active_htlcs; + a & m_active_htlcs_txid; + a & m_own_asset_descriptors; + a & m_custom_assets; + a & m_rollback_events; + a & m_whitelisted_assets; } - //---------------------------------------------------------------------------------------------------- - inline void null_split_strategy(const std::vector& dsts, - const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, - std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) - { - splitted_dsts = dsts; - - dust = 0; - uint64_t change = change_dst.amount; - if (0 < dust_threshold) - { - for (uint64_t order = 10; order <= 10 * dust_threshold; order *= 10) - { - uint64_t dust_candidate = change_dst.amount % order; - uint64_t change_candidate = (change_dst.amount / order) * order; - if (dust_candidate <= dust_threshold) - { - dust = dust_candidate; - change = change_candidate; - } - else - { - break; - } - } - } - - if (0 != change) - { - splitted_dsts.push_back(currency::tx_destination_entry(change, change_dst.addr)); - } - } - //---------------------------------------------------------------------------------------------------- - inline void void_split_strategy(const std::vector& dsts, - const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, - std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) - { - splitted_dsts.insert(splitted_dsts.end(), dsts.begin(), dsts.end()); - if (change_dst.amount > 0) - splitted_dsts.push_back(change_dst); - } - //---------------------------------------------------------------------------------------------------- - enum split_strategy_id_t { ssi_none = 0, ssi_digit = 1, ssi_null = 2, ssi_void = 3 }; - //---------------------------------------------------------------------------------------------------- - inline bool apply_split_strategy_by_id(split_strategy_id_t id, const std::vector& dsts, - const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, - std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) - { - switch (id) - { - case ssi_digit: - digit_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed); - return true; - case ssi_null: - null_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed); - return true; - case ssi_void: - void_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed); - return true; - default: - return false; - } - } - - } // namespace detail - - struct construct_tx_param - { - // preparing data for tx - std::vector dsts; - size_t fake_outputs_count = 0; - uint64_t fee = 0; - tx_dust_policy dust_policy; - crypto::hash multisig_id = currency::null_hash; - uint8_t flags = 0; - uint8_t split_strategy_id = 0; - bool mark_tx_as_complete = false; - - crypto::hash htlc_tx_id; - std::string htlc_origin; - - // constructing tx - uint64_t unlock_time = 0; - std::vector extra; - std::vector attachments; - currency::account_public_address crypt_address; - uint8_t tx_outs_attr = 0; - bool shuffle = false; - bool create_utxo_defragmentation_tx = false; - bool need_at_least_1_zc = false; - crypto::secret_key asset_deploy_control_key = currency::null_skey; - }; - - struct mode_separate_context - { - currency::transaction tx_for_mode_separate; - view::ionic_swap_proposal_info proposal_info; - bool escrow = false; }; - struct selection_for_amount - { - uint64_t needed_amount = 0; - uint64_t found_amount = 0; - //std::vector selected_indicies; - }; - typedef std::unordered_map assets_selection_context; - - class wallet2: public tools::tor::t_transport_state_notifier, public boost::static_visitor + class wallet2: public tools::tor::t_transport_state_notifier, public boost::static_visitor, public wallet2_base_state { wallet2(const wallet2&) = delete; public: wallet2(); static std::string transfer_flags_to_str(uint32_t flags); - static std::string transform_tx_to_str(const currency::transaction& tx); - static currency::transaction transform_str_to_tx(const std::string& tx_str); - //general rollback mechanism - struct asset_register_event - { - crypto::public_key asset_id = currency::null_pkey; - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(asset_id) - END_BOOST_SERIALIZATION() - - }; - - struct wallet_own_asset_context - { - currency::asset_descriptor_base asset_descriptor; - crypto::secret_key control_key; - //uint64_t height = 0; - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(asset_descriptor) - BOOST_SERIALIZE(control_key) - //BOOST_SERIALIZE(height) - END_BOOST_SERIALIZATION() - }; - - struct asset_update_event - { - crypto::public_key asset_id = currency::null_pkey; - wallet_own_asset_context own_context; - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(asset_id) - BOOST_SERIALIZE(own_context) - END_BOOST_SERIALIZATION() - }; - - struct asset_unown_event - { - crypto::public_key asset_id = currency::null_pkey; - wallet_own_asset_context own_context; - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(asset_id) - BOOST_SERIALIZE(own_context) - END_BOOST_SERIALIZATION() - }; - - typedef boost::variant wallet_event_t; - - struct transaction_wallet_info - { - uint64_t m_block_height = 0; - uint64_t m_block_timestamp = 0; - currency::transaction m_tx; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(m_block_height) - KV_SERIALIZE(m_block_timestamp) - KV_SERIALIZE_CUSTOM(m_tx, std::string, tools::wallet2::transform_tx_to_str, tools::wallet2::transform_str_to_tx) - END_KV_SERIALIZE_MAP() - }; - - static const transaction_wallet_info& transform_ptr_to_value(const std::shared_ptr& a); - static std::shared_ptr transform_value_to_ptr(const transaction_wallet_info& d); - - struct transfer_details_base; - static uint64_t transfer_details_base_to_amount(const transfer_details_base& tdb); - static std::string transfer_details_base_to_tx_hash(const transfer_details_base& tdb); - - struct transfer_details_base - { - struct ZC_out_info // TODO: @#@# consider using wallet_out_info instead - { - ZC_out_info() = default; - ZC_out_info(const crypto::scalar_t& amount_blinding_mask, const crypto::scalar_t& asset_id_blinding_mask, const crypto::public_key& asset_id) - : amount_blinding_mask(amount_blinding_mask), asset_id_blinding_mask(asset_id_blinding_mask), asset_id(asset_id) - {} - crypto::scalar_t amount_blinding_mask = 0; - crypto::scalar_t asset_id_blinding_mask = 0; - crypto::public_key asset_id = currency::null_pkey; // not blinded, not multiplied by 1/8 TODO: @#@# consider changing to point_t, also consider using wallet wallet_out_info - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(amount_blinding_mask) - KV_SERIALIZE(asset_id_blinding_mask) - KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) - END_KV_SERIALIZE_MAP() - }; - - std::shared_ptr m_ptx_wallet_info; - uint64_t m_internal_output_index = 0; - uint64_t m_spent_height = 0; - uint32_t m_flags = 0; - uint64_t m_amount = 0; - boost::shared_ptr m_zc_info_ptr; - - uint64_t amount() const { return m_amount; } - uint64_t amount_for_global_output_index() const { return is_zc() ? 0 : m_amount; } // amount value for global outputs index, it's zero for outputs with hidden amounts - - // @#@ will throw if type is not tx_out_bare, TODO: change according to new model, - // need to replace all get_tx_out_bare_from_out_v() to proper code - //const currency::tx_out_bare& output() const { return currency::get_tx_out_bare_from_out_v(m_ptx_wallet_info->m_tx.vout[m_internal_output_index]); } - - const currency::tx_out_v& output() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index]; } - uint8_t mix_attr() const { uint8_t result = UINT8_MAX; get_mix_attr_from_tx_out_v(output(), result); return result; } - crypto::hash tx_hash() const { return get_transaction_hash(m_ptx_wallet_info->m_tx); } - bool is_spent() const { return m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT; } - bool is_spendable() const { return (m_flags & (WALLET_TRANSFER_DETAIL_FLAG_SPENT | WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION | WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION)) == 0; } - bool is_reserved_for_escrow() const { return ( (m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) != 0 ); } - bool is_zc() const { return m_zc_info_ptr.get(); } - const crypto::public_key& get_asset_id() const { if (m_zc_info_ptr.get()) { return m_zc_info_ptr->asset_id; } else { return currency::native_coin_asset_id; } } - bool is_native_coin() const { return m_zc_info_ptr.get() ? (m_zc_info_ptr->asset_id == currency::native_coin_asset_id) : true; } - bool is_htlc() const { - - if (m_ptx_wallet_info->m_tx.vout[m_internal_output_index].type() == typeid(currency::tx_out_bare) && - boost::get(m_ptx_wallet_info->m_tx.vout[m_internal_output_index]).target.type() == typeid(currency::txout_htlc)) - return true; - return false; - } - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_CUSTOM(m_ptx_wallet_info, const transaction_wallet_info&, tools::wallet2::transform_ptr_to_value, tools::wallet2::transform_value_to_ptr) - KV_SERIALIZE(m_internal_output_index) - KV_SERIALIZE(m_spent_height) - KV_SERIALIZE(m_flags) - KV_SERIALIZE(m_amount) - KV_SERIALIZE_N(m_zc_info_ptr, "zc_out_info") - KV_SERIALIZE_EPHEMERAL_N(uint64_t, tools::wallet2::transfer_details_base_to_amount, "amount") - KV_SERIALIZE_EPHEMERAL_N(std::string, tools::wallet2::transfer_details_base_to_tx_hash, "tx_id") - END_KV_SERIALIZE_MAP() - - }; - - - struct transfer_details_extra_option_htlc_info - { - std::string origin; //this field filled only if htlc had been redeemed - crypto::hash redeem_tx_id = currency::null_hash; - }; - - - typedef boost::variant transfer_details_extra_options_v; - - struct transfer_details : public transfer_details_base - { - uint64_t m_global_output_index = 0; - crypto::key_image m_key_image; //TODO: key_image stored twice :( - std::vector varian_options; - - //v2 - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(m_global_output_index) - KV_SERIALIZE_POD_AS_HEX_STRING(m_key_image) - KV_CHAIN_BASE(transfer_details_base) - END_KV_SERIALIZE_MAP() - }; - - //used in wallet - struct htlc_expiration_trigger - { - bool is_wallet_owns_redeem = false; //specify if this HTLC belong to this wallet by pkey_redeem or by pkey_refund - uint64_t transfer_index = 0; - }; - - - struct payment_details_subtransfer - { - crypto::public_key asset_id = currency::null_pkey; - uint64_t amount = 0; - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(asset_id) - BOOST_SERIALIZE(amount) - END_BOOST_SERIALIZATION() - }; - - struct payment_details - { - crypto::hash m_tx_hash = currency::null_hash; - uint64_t m_amount = 0; // native coins amount - uint64_t m_block_height = 0; - uint64_t m_unlock_time = 0; - std::vector subtransfers; //subtransfers added for confidential asset only, native amount should be stored in m_amount (for space saving) - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(m_tx_hash) - BOOST_SERIALIZE(m_amount) - BOOST_SERIALIZE(m_block_height) - BOOST_SERIALIZE(m_unlock_time) - BOOST_SERIALIZE(subtransfers) - END_BOOST_SERIALIZATION() - }; + struct mining_context : public currency::pos_mining_context { @@ -528,20 +248,6 @@ namespace tools uint64_t total_amount_checked = 0; }; - struct expiration_entry_info - { - std::vector selected_transfers; - uint64_t expiration_time = 0; - crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx) - std::vector receved; - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(selected_transfers) - BOOST_SERIALIZE(expiration_time) - BOOST_SERIALIZE(related_tx_id) - BOOST_SERIALIZE(receved) - END_BOOST_SERIALIZATION() - }; /* This might be not the best solution so far, but after discussion with @sowle we came up to conclusion @@ -559,17 +265,6 @@ namespace tools }; - - typedef std::unordered_multimap payment_container; - - typedef std::deque transfer_container; - typedef std::unordered_map multisig_transfer_container; - typedef std::unordered_map escrow_contracts_container; - typedef std::map > free_amounts_cache_type; - typedef std::unordered_map free_assets_amounts_cache_type; - typedef std::unordered_map, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid - - struct keys_file_data_old { crypto::chacha8_iv iv; @@ -700,6 +395,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; @@ -832,7 +528,7 @@ namespace tools bool scan_pos(mining_context& cxt, std::atomic& stop, idle_condition_cb_t idle_condition_cb, const currency::core_runtime_config &runtime_config); bool fill_mining_context(mining_context& ctx); - void get_transfers(wallet2::transfer_container& incoming_transfers) const; + void get_transfers(transfer_container& incoming_transfers) const; std::string get_transfers_str(bool include_spent = true, bool include_unspent = true, bool show_only_unknown = false, const std::string& filter_asset_ticker = std::string{}) const; std::string get_balance_str() const; @@ -868,61 +564,7 @@ namespace tools template inline void serialize(t_archive &a, const unsigned int ver) { - if (t_archive::is_saving::value) - { - WLT_LOG_MAGENTA("Serializing file with ver: " << ver, LOG_LEVEL_0); - } - - - // do not load wallet if data version is greather than the code version - if (ver > WALLET_FILE_SERIALIZATION_VERSION) - { - WLT_LOG_MAGENTA("Wallet file truncated due to WALLET_FILE_SERIALIZATION_VERSION is more then curren build", LOG_LEVEL_0); - return; - } - if(ver < WALLET_FILE_LAST_SUPPORTED_VERSION) - { - WLT_LOG_MAGENTA("Wallet file truncated due to ver(" << ver << ") is less then WALLET_FILE_LAST_SUPPORTED_VERSION", LOG_LEVEL_0); - return; - } - - if (t_archive::is_saving::value) - { - uint64_t formation_ver = CURRENCY_FORMATION_VERSION; - a & formation_ver; - } - else - { - uint64_t formation_ver = 0; - a & formation_ver; - if (formation_ver != CURRENCY_FORMATION_VERSION) - { - WLT_LOG_MAGENTA("Wallet file truncated due to mismatch CURRENCY_FORMATION_VERSION", LOG_LEVEL_0); - return; - } - } - //convert from old version - a & m_chain; - a & m_minimum_height; - a & m_amount_gindex_to_transfer_id; - a & m_transfers; - a & m_multisig_transfers; - a & m_key_images; - a & m_unconfirmed_txs; - a & m_unconfirmed_multisig_transfers; - a & m_payments; - a & m_transfer_history; - a & m_unconfirmed_in_transfers; - a & m_contracts; - a & m_money_expirations; - a & m_pending_key_images; - a & m_tx_keys; - a & m_last_pow_block_h; - a & m_htlcs; - a & m_active_htlcs; - a & m_active_htlcs_txid; - a & m_own_asset_descriptors; - a & m_custom_assets; + wallet2_base_state::serialize(a, ver); } bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count); @@ -953,6 +595,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; @@ -1010,6 +653,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 @@ -1021,6 +666,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, @@ -1047,6 +695,7 @@ namespace tools protected: epee::misc_utils::events_dispatcher m_debug_events_dispatcher; + private: // -------- t_transport_state_notifier ------------------------------------------------ @@ -1127,6 +776,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); @@ -1197,71 +847,57 @@ private: static void wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); static void wti_to_json_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + + + /* + + !!!!! IMPORTAN !!!!! + + All variables that supposed to hold wallet state of synchronization(i.e. transfers, assets, htlc, swaps, contracts) - should + be placed in wallet2_base_state base class to avoid typical bugs when it's forgotten to be included in reset/resync/serialize functions + + */ + + + currency::account_base m_account; bool m_watch_only; std::string m_log_prefix; // part of pub address, prefix for logging functions std::wstring m_wallet_file; std::wstring m_pending_ki_file; std::string m_password; - uint64_t m_minimum_height; + - std::atomic m_last_bc_timestamp; bool m_do_rise_transfer; 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; - - transfer_container m_transfers; - multisig_transfer_container m_multisig_transfers; - amount_gindex_to_transfer_id_container m_amount_gindex_to_transfer_id; - payment_container m_payments; - std::unordered_map m_key_images; - std::unordered_map m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key + 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 std::atomic m_stop; - std::vector m_transfer_history; - std::unordered_map m_unconfirmed_in_transfers; - std::unordered_map m_unconfirmed_txs; - 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 - mutable std::unordered_map m_whitelisted_assets; //assets that whitelisted - - - 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 - std::unordered_map m_active_htlcs_txid; // map [txid] -> transfer index, limitation: 1 transactiom -> 1 htlc - + mutable std::atomic m_whitelist_updated = false; std::shared_ptr m_core_proxy; std::shared_ptr m_wcallback; - uint64_t m_height_of_start_sync; - std::atomic m_last_sync_percent; - uint64_t m_last_pow_block_h; - currency::core_runtime_config m_core_runtime_config; - escrow_contracts_container m_contracts; - wallet_chain_shortener m_chain; - std::list m_money_expirations; - //optimization for big wallets and batch tx + + currency::core_runtime_config m_core_runtime_config; + //optimization for big wallets and batch tx free_assets_amounts_cache_type m_found_free_amounts; uint64_t m_fake_outputs_count; std::string m_miner_text_info; - mutable uint64_t m_current_wallet_file_size; bool m_use_deffered_global_outputs; 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; - - std::list> m_rollback_events; - - }; // class wallet2 } // namespace tools @@ -1269,71 +905,56 @@ private: BOOST_CLASS_VERSION(tools::wallet2, WALLET_FILE_SERIALIZATION_VERSION) BOOST_CLASS_VERSION(tools::wallet_public::wallet_transfer_info, 12) -BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 3) -BOOST_CLASS_VERSION(tools::wallet2::transfer_details_base, 2) namespace boost { namespace serialization { - template - inline void serialize(Archive &a, tools::wallet2::transaction_wallet_info &x, const boost::serialization::version_type ver) - { - a & x.m_block_height; - a & x.m_block_timestamp; - a & x.m_tx; - } - template - inline void serialize(Archive& a, tools::wallet2::transfer_details_base::ZC_out_info& x, const boost::serialization::version_type ver) - { - a & x.amount_blinding_mask; - a & x.asset_id_blinding_mask; - a & x.asset_id; - } +// template +// inline void serialize(Archive &a, tools::transfer_details &x, const boost::serialization::version_type ver) +// { +// a & x.m_global_output_index; +// a & x.m_key_image; +// a & static_cast(x); +// if (ver < 3) +// return; +// a & x.varian_options; +// } - template - inline void serialize(Archive &a, tools::wallet2::transfer_details_base &x, const boost::serialization::version_type ver) - { - a & x.m_ptx_wallet_info; - a & x.m_internal_output_index; - a & x.m_flags; - a & x.m_spent_height; - if (ver < 2) - { - x.m_amount = get_amount_from_variant(x.output()); - return; - } - a & x.m_amount; - a & x.m_zc_info_ptr; - } - - - template - inline void serialize(Archive &a, tools::wallet2::transfer_details_extra_option_htlc_info &x, const boost::serialization::version_type ver) - { - a & x.origin; - } - - - template - inline void serialize(Archive &a, tools::wallet2::transfer_details &x, const boost::serialization::version_type ver) - { - a & x.m_global_output_index; - a & x.m_key_image; - a & static_cast(x); - if (ver < 3) - return; - a & x.varian_options; - } - - template - inline void serialize(Archive &a, tools::wallet2::htlc_expiration_trigger &x, const boost::serialization::version_type ver) - { - a & x.is_wallet_owns_redeem; - a & x.transfer_index; - } + /*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/wallet2_base.h b/src/wallet/wallet2_base.h new file mode 100644 index 00000000..52da0c59 --- /dev/null +++ b/src/wallet/wallet2_base.h @@ -0,0 +1,523 @@ +// Copyright (c) 2014-2023 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// 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. + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "include_base_utils.h" +#include "profile_tools.h" +#include "sync_locked_object.h" + + +#include "currency_core/currency_boost_serialization.h" +#include "currency_core/account_boost_serialization.h" +#include "currency_core/currency_format_utils.h" + +#include "common/make_hashable.h" +#include "wallet_public_structs_defs.h" +#include "currency_core/currency_format_utils.h" +#include "common/unordered_containers_boost_serialization.h" +#include "common/atomics_boost_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "crypto/chacha8.h" +#include "crypto/hash.h" +#include "core_rpc_proxy.h" +#include "core_default_rpc_proxy.h" +#include "wallet_errors.h" +#include "currency_core/core_runtime_config.h" +#include "currency_core/bc_offers_serialization.h" +#include "currency_core/bc_escrow_service.h" +#include "common/pod_array_file_container.h" +#include "wallet_chain_shortener.h" +#include "tor-connect/torlib/tor_lib_iface.h" +#include "currency_core/pos_mining.h" +#include "view_iface.h" + + +#define WALLET_TRANSFER_DETAIL_FLAG_SPENT uint32_t(1 << 0) +#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED uint32_t(1 << 1) +#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION uint32_t(1 << 2) +#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3) +#define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing) +#define WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM uint32_t(1 << 5) // for htlc keeps info if this htlc belong as redeem or as refund + + + +namespace tools +{ + +#pragma pack(push, 1) + struct out_key_to_ki + { + crypto::public_key out_key; + crypto::key_image key_image; + }; +#pragma pack(pop) + + typedef tools::pod_array_file_container pending_ki_file_container_t; + + namespace detail + { + //---------------------------------------------------------------------------------------------------- + inline void digit_split_strategy(const std::vector& dsts, + const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, + std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) + { + splitted_dsts.clear(); + dust = 0; + + for (auto& de : dsts) + { + if (de.addr.size() > 1) + { + //for multisig we don't split + splitted_dsts.push_back(de); + } + else if (de.htlc_options.expiration != 0) + { + //for htlc we don't do split + splitted_dsts.push_back(de); + } + else + { + currency::decompose_amount_into_digits(de.amount, dust_threshold, + [&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, de.addr, de.asset_id)); }, + [&](uint64_t a_dust) { splitted_dsts.push_back(currency::tx_destination_entry(a_dust, de.addr, de.asset_id)); }, max_output_allowed); + } + } + + if (change_dst.amount > 0) + { + if (change_dst.addr.size() > 1) + { + //for multisig we don't split + splitted_dsts.push_back(change_dst); + } + else + { + currency::decompose_amount_into_digits(change_dst.amount, dust_threshold, + [&](uint64_t chunk) { splitted_dsts.push_back(currency::tx_destination_entry(chunk, change_dst.addr)); }, + [&](uint64_t a_dust) { dust = a_dust; }, max_output_allowed); + } + } + } + //---------------------------------------------------------------------------------------------------- + inline void null_split_strategy(const std::vector& dsts, + const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, + std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) + { + splitted_dsts = dsts; + + dust = 0; + uint64_t change = change_dst.amount; + if (0 < dust_threshold) + { + for (uint64_t order = 10; order <= 10 * dust_threshold; order *= 10) + { + uint64_t dust_candidate = change_dst.amount % order; + uint64_t change_candidate = (change_dst.amount / order) * order; + if (dust_candidate <= dust_threshold) + { + dust = dust_candidate; + change = change_candidate; + } + else + { + break; + } + } + } + + if (0 != change) + { + splitted_dsts.push_back(currency::tx_destination_entry(change, change_dst.addr)); + } + } + //---------------------------------------------------------------------------------------------------- + inline void void_split_strategy(const std::vector& dsts, + const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, + std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) + { + splitted_dsts.insert(splitted_dsts.end(), dsts.begin(), dsts.end()); + if (change_dst.amount > 0) + splitted_dsts.push_back(change_dst); + } + //---------------------------------------------------------------------------------------------------- + enum split_strategy_id_t { ssi_none = 0, ssi_digit = 1, ssi_null = 2, ssi_void = 3 }; + //---------------------------------------------------------------------------------------------------- + inline bool apply_split_strategy_by_id(split_strategy_id_t id, const std::vector& dsts, + const currency::tx_destination_entry& change_dst, uint64_t dust_threshold, + std::vector& splitted_dsts, uint64_t& dust, uint64_t max_output_allowed) + { + switch (id) + { + case ssi_digit: + digit_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed); + return true; + case ssi_null: + null_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed); + return true; + case ssi_void: + void_split_strategy(dsts, change_dst, dust_threshold, splitted_dsts, dust, max_output_allowed); + return true; + default: + return false; + } + } + + } // namespace detail + + struct tx_dust_policy + { + uint64_t dust_threshold = 0; + bool add_to_fee = false; + currency::account_public_address addr_for_dust; + + tx_dust_policy(uint64_t a_dust_threshold = DEFAULT_DUST_THRESHOLD, bool an_add_to_fee = true, currency::account_public_address an_addr_for_dust = currency::account_public_address()) + : dust_threshold(a_dust_threshold) + , add_to_fee(an_add_to_fee) + , addr_for_dust(an_addr_for_dust) + { + } + + BEGIN_SERIALIZE_OBJECT() + FIELD(dust_threshold) + FIELD(add_to_fee) + FIELD(addr_for_dust) + END_SERIALIZE() + }; + + struct construct_tx_param + { + // preparing data for tx + std::vector dsts; + size_t fake_outputs_count = 0; + uint64_t fee = 0; + tx_dust_policy dust_policy; + crypto::hash multisig_id = currency::null_hash; + uint8_t flags = 0; + uint8_t split_strategy_id = 0; + bool mark_tx_as_complete = false; + + crypto::hash htlc_tx_id; + std::string htlc_origin; + + // constructing tx + uint64_t unlock_time = 0; + std::vector extra; + std::vector attachments; + currency::account_public_address crypt_address; + uint8_t tx_outs_attr = 0; + bool shuffle = false; + bool create_utxo_defragmentation_tx = false; + bool need_at_least_1_zc = false; + crypto::secret_key asset_deploy_control_key = currency::null_skey; + }; + + struct mode_separate_context + { + currency::transaction tx_for_mode_separate; + view::ionic_swap_proposal_info proposal_info; + bool escrow = false; + }; + + + struct selection_for_amount + { + uint64_t needed_amount = 0; + uint64_t found_amount = 0; + //std::vector selected_indicies; + }; + typedef std::unordered_map assets_selection_context; + + //general rollback mechanism + struct asset_register_event + { + crypto::public_key asset_id = currency::null_pkey; + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(asset_id) + END_BOOST_SERIALIZATION() + + }; + + struct wallet_own_asset_context + { + currency::asset_descriptor_base asset_descriptor; + crypto::secret_key control_key; + //uint64_t height = 0; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(asset_descriptor) + BOOST_SERIALIZE(control_key) + //BOOST_SERIALIZE(height) + END_BOOST_SERIALIZATION() + }; + + struct asset_update_event + { + crypto::public_key asset_id = currency::null_pkey; + wallet_own_asset_context own_context; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(asset_id) + BOOST_SERIALIZE(own_context) + END_BOOST_SERIALIZATION() + }; + + struct asset_unown_event + { + crypto::public_key asset_id = currency::null_pkey; + wallet_own_asset_context own_context; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(asset_id) + BOOST_SERIALIZE(own_context) + END_BOOST_SERIALIZATION() + }; + + typedef boost::variant wallet_event_t; + + struct transaction_wallet_info + { + uint64_t m_block_height = 0; + uint64_t m_block_timestamp = 0; + currency::transaction m_tx; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_block_height) + KV_SERIALIZE(m_block_timestamp) + KV_SERIALIZE_CUSTOM(m_tx, std::string, currency::transform_tx_to_str, currency::transform_str_to_tx) + END_KV_SERIALIZE_MAP() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(m_block_height) + BOOST_SERIALIZE(m_block_timestamp) + BOOST_SERIALIZE(m_tx) + END_BOOST_SERIALIZATION() + + }; + + + namespace detail + { + //---------------------------------------------------------------------------------------------------- + inline const transaction_wallet_info& transform_ptr_to_value(const std::shared_ptr& a) + { + return *a; + } + //---------------------------------------------------------------------------------------------------- + inline std::shared_ptr transform_value_to_ptr(const transaction_wallet_info& d) + { + THROW_IF_TRUE_WALLET_INT_ERR_EX_NO_HANDLER(false, "transform_value_to_ptr shoruld never be called"); + return std::shared_ptr(); + } + //---------------------------------------------------------------------------------------------------- + } + + + struct transfer_details_base + { + struct ZC_out_info // TODO: @#@# consider using wallet_out_info instead + { + ZC_out_info() = default; + ZC_out_info(const crypto::scalar_t& amount_blinding_mask, const crypto::scalar_t& asset_id_blinding_mask, const crypto::public_key& asset_id) + : amount_blinding_mask(amount_blinding_mask), asset_id_blinding_mask(asset_id_blinding_mask), asset_id(asset_id) + {} + crypto::scalar_t amount_blinding_mask = 0; + crypto::scalar_t asset_id_blinding_mask = 0; + crypto::public_key asset_id = currency::null_pkey; // not blinded, not multiplied by 1/8 TODO: @#@# consider changing to point_t, also consider using wallet wallet_out_info + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount_blinding_mask) + KV_SERIALIZE(asset_id_blinding_mask) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + END_KV_SERIALIZE_MAP() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(amount_blinding_mask) + BOOST_SERIALIZE(asset_id_blinding_mask) + BOOST_SERIALIZE(asset_id) + END_BOOST_SERIALIZATION() + }; + + std::shared_ptr m_ptx_wallet_info; + uint64_t m_internal_output_index = 0; + uint64_t m_spent_height = 0; + uint32_t m_flags = 0; + uint64_t m_amount = 0; + boost::shared_ptr m_zc_info_ptr; + + uint64_t amount() const { return m_amount; } + uint64_t amount_for_global_output_index() const { return is_zc() ? 0 : m_amount; } // amount value for global outputs index, it's zero for outputs with hidden amounts + + // @#@ will throw if type is not tx_out_bare, TODO: change according to new model, + // need to replace all get_tx_out_bare_from_out_v() to proper code + //const currency::tx_out_bare& output() const { return currency::get_tx_out_bare_from_out_v(m_ptx_wallet_info->m_tx.vout[m_internal_output_index]); } + + const currency::tx_out_v& output() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index]; } + uint8_t mix_attr() const { uint8_t result = UINT8_MAX; get_mix_attr_from_tx_out_v(output(), result); return result; } + crypto::hash tx_hash() const { return get_transaction_hash(m_ptx_wallet_info->m_tx); } + bool is_spent() const { return m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT; } + bool is_spendable() const { return (m_flags & (WALLET_TRANSFER_DETAIL_FLAG_SPENT | WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION | WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION)) == 0; } + bool is_reserved_for_escrow() const { return ((m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) != 0); } + bool is_zc() const { return m_zc_info_ptr.get(); } + const crypto::public_key& get_asset_id() const { if (m_zc_info_ptr.get()) { return m_zc_info_ptr->asset_id; } else { return currency::native_coin_asset_id; } } + bool is_native_coin() const { return m_zc_info_ptr.get() ? (m_zc_info_ptr->asset_id == currency::native_coin_asset_id) : true; } + bool is_htlc() const { + + if (m_ptx_wallet_info->m_tx.vout[m_internal_output_index].type() == typeid(currency::tx_out_bare) && + boost::get(m_ptx_wallet_info->m_tx.vout[m_internal_output_index]).target.type() == typeid(currency::txout_htlc)) + return true; + return false; + } + static inline uint64_t transfer_details_base_to_amount(const transfer_details_base& tdb) + { + return tdb.amount(); + } + //---------------------------------------------------------------------------------------------------- + static inline std::string transfer_details_base_to_tx_hash(const transfer_details_base& tdb) + { + return epee::string_tools::pod_to_hex(currency::get_transaction_hash(tdb.m_ptx_wallet_info->m_tx)); + } + + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CUSTOM(m_ptx_wallet_info, const transaction_wallet_info&, detail::transform_ptr_to_value, detail::transform_value_to_ptr) + KV_SERIALIZE(m_internal_output_index) + KV_SERIALIZE(m_spent_height) + KV_SERIALIZE(m_flags) + KV_SERIALIZE(m_amount) + KV_SERIALIZE_N(m_zc_info_ptr, "zc_out_info") + KV_SERIALIZE_EPHEMERAL_N(uint64_t, transfer_details_base_to_amount, "amount") + KV_SERIALIZE_EPHEMERAL_N(std::string, transfer_details_base_to_tx_hash, "tx_id") + END_KV_SERIALIZE_MAP() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(m_ptx_wallet_info) + BOOST_SERIALIZE(m_internal_output_index) + BOOST_SERIALIZE(m_flags) + BOOST_SERIALIZE(m_spent_height) + BOOST_SERIALIZE(m_amount) + BOOST_SERIALIZE(m_zc_info_ptr) + END_BOOST_SERIALIZATION() + }; + + + + + struct transfer_details_extra_option_htlc_info + { + std::string origin; //this field filled only if htlc had been redeemed + crypto::hash redeem_tx_id = currency::null_hash; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(origin) + BOOST_SERIALIZE(redeem_tx_id) + END_BOOST_SERIALIZATION() + }; + + + typedef boost::variant transfer_details_extra_options_v; + + struct transfer_details : public transfer_details_base + { + uint64_t m_global_output_index = 0; + crypto::key_image m_key_image; //TODO: key_image stored twice :( + std::vector varian_options; + + //v2 + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_global_output_index) + KV_SERIALIZE_POD_AS_HEX_STRING(m_key_image) + KV_CHAIN_BASE(transfer_details_base) + END_KV_SERIALIZE_MAP() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(m_global_output_index) + BOOST_SERIALIZE(m_key_image) + BOOST_SERIALIZE_BASE_CLASS(transfer_details_base) + BOOST_SERIALIZE(varian_options) + END_BOOST_SERIALIZATION() + }; + + //used in wallet + struct htlc_expiration_trigger + { + bool is_wallet_owns_redeem = false; //specify if this HTLC belong to this wallet by pkey_redeem or by pkey_refund + uint64_t transfer_index = 0; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(is_wallet_owns_redeem) + BOOST_SERIALIZE(transfer_index) + END_BOOST_SERIALIZATION() + }; + + + struct payment_details_subtransfer + { + crypto::public_key asset_id = currency::null_pkey; + uint64_t amount = 0; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(asset_id) + BOOST_SERIALIZE(amount) + END_BOOST_SERIALIZATION() + }; + + struct payment_details + { + crypto::hash m_tx_hash = currency::null_hash; + uint64_t m_amount = 0; // native coins amount + uint64_t m_block_height = 0; + uint64_t m_unlock_time = 0; + std::vector subtransfers; //subtransfers added for confidential asset only, native amount should be stored in m_amount (for space saving) + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(m_tx_hash) + BOOST_SERIALIZE(m_amount) + BOOST_SERIALIZE(m_block_height) + BOOST_SERIALIZE(m_unlock_time) + BOOST_SERIALIZE(subtransfers) + END_BOOST_SERIALIZATION() + }; + + struct expiration_entry_info + { + std::vector selected_transfers; + uint64_t expiration_time = 0; + crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx) + std::vector receved; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(selected_transfers) + BOOST_SERIALIZE(expiration_time) + BOOST_SERIALIZE(related_tx_id) + BOOST_SERIALIZE(receved) + END_BOOST_SERIALIZATION() + }; + + typedef std::unordered_multimap payment_container; + + typedef std::deque transfer_container; + typedef std::unordered_map multisig_transfer_container; + typedef std::unordered_map escrow_contracts_container; + typedef std::map > free_amounts_cache_type; + typedef std::unordered_map free_assets_amounts_cache_type; + typedef std::unordered_map, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid + +}// namespace tools + +BOOST_CLASS_VERSION(tools::transfer_details, 3) +BOOST_CLASS_VERSION(tools::transfer_details_base, 2) diff --git a/src/wallet/wallet_chain_shortener.cpp b/src/wallet/wallet_chain_shortener.cpp index e353c1a6..77c5d82c 100644 --- a/src/wallet/wallet_chain_shortener.cpp +++ b/src/wallet/wallet_chain_shortener.cpp @@ -15,10 +15,7 @@ static void exception_handler(){} -wallet_chain_shortener::wallet_chain_shortener(): m_genesis(currency::gdefault_genesis) -{ - m_local_bc_size = 1; -} + void wallet_chain_shortener::clear() { m_local_bc_size = 1; diff --git a/src/wallet/wallet_chain_shortener.h b/src/wallet/wallet_chain_shortener.h index 500c2494..e3d851ca 100644 --- a/src/wallet/wallet_chain_shortener.h +++ b/src/wallet/wallet_chain_shortener.h @@ -18,12 +18,11 @@ #include "include_base_utils.h" #include "crypto/crypto.h" - +#include "currency_core/currency_basic.h" class wallet_chain_shortener { public: - wallet_chain_shortener(); void push_new_block_id(const crypto::hash& id, uint64_t height); uint64_t get_top_block_height() const; uint64_t get_blockchain_current_size() const; @@ -48,8 +47,8 @@ public: //debug functions std::string get_internal_state_text() const; private: - std::atomic m_local_bc_size; //temporary workaround - crypto::hash m_genesis; + std::atomic m_local_bc_size = 1; //temporary workaround + crypto::hash m_genesis = currency::gdefault_genesis; std::map m_last_20_blocks; std::map m_last_144_blocks_every_10; //1 day std::map m_last_144_blocks_every_100; //10 days 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 223cd8ae..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; } //------------------------------------------------------------------------------------------------------------------------------ @@ -448,7 +451,7 @@ namespace tools } res.payments.clear(); - std::list payment_list; + std::list payment_list; w.get_wallet()->get_payments(payment_id, payment_list); for (auto payment : payment_list) { @@ -486,7 +489,7 @@ namespace tools return false; } - std::list payment_list; + std::list payment_list; w.get_wallet()->get_payments(payment_id, payment_list, req.min_block_height); for (auto & payment : payment_list) @@ -772,7 +775,7 @@ namespace tools bool wallet_rpc_server::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) { WALLET_RPC_BEGIN_TRY_ENTRY(); - tools::wallet2::escrow_contracts_container ecc; + tools::escrow_contracts_container ecc; w.get_wallet()->get_contracts(ecc); res.contracts.resize(ecc.size()); size_t i = 0; 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 3889ea4c..98d22bc6 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) @@ -1669,7 +1675,7 @@ std::string wallets_manager::get_wallet_info_extra(uint64_t wallet_id, view::wal std::string wallets_manager::get_contracts(size_t wallet_id, std::vector& contracts) { - tools::wallet2::escrow_contracts_container cc; + tools::escrow_contracts_container cc; GET_WALLET_OPT_BY_ID(wallet_id, w); try { @@ -1693,7 +1699,7 @@ std::string wallets_manager::get_contracts(size_t wallet_id, std::vectorget()->get_account().get_public_address_str(), LOG_LEVEL_0); epee::math_helper::once_a_time_seconds scan_pool_interval; - epee::math_helper::once_a_time_seconds pos_minin_interval; + epee::math_helper::once_a_time_seconds<2> pos_minin_interval; view::wallet_status_info wsi = AUTO_VAL_INIT(wsi); while (!major_stop) { 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 b16e24ee..fde7294e 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; @@ -634,7 +636,7 @@ bool test_generator::find_kernel(const std::list& accs, found_timestamp = context.sk.block_timestamp; found_kh = crypto::cn_fast_hash(&context.sk, sizeof(context.sk)); // TODO: consider passing kernel_hash from scan_pos and do_pos_mining_iteration - tools::wallet2::transfer_details td = AUTO_VAL_INIT(td); + tools::transfer_details td = AUTO_VAL_INIT(td); r = w->get_transfer_info_by_index(context.index, td); CHECK_AND_NO_ASSERT_MES(r, false, "get_transfer_info_by_index() failed for index " << context.index); @@ -1456,7 +1458,7 @@ bool fill_tx_sources(std::vector& sources, const std: } } - uint64_t head_block_ts = get_actual_timestamp(blk_head); + uint64_t head_block_ts = get_block_datetime(blk_head); uint64_t next_block_height = blockchain.size(); // Iterate in reverse is more efficiency @@ -2151,18 +2153,18 @@ bool make_tx_multisig_to_key(const currency::transaction& source_tx, bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result, bool substruct_change_from_result /* = true */) { - std::deque transfers; + std::deque transfers; w.get_transfers(transfers); result = 0; - for (const tools::wallet2::transfer_details& td : transfers) + for (const tools::transfer_details& td : transfers) { if (td.m_flags == (WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION)) result += td.amount(); } if (substruct_change_from_result) { - const std::list& ee = w.get_expiration_entries(); + const std::list& ee = w.get_expiration_entries(); for (auto &e : ee) { uint64_t change_amount_native = 0; diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index e1029aae..97dd5bce 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -819,47 +819,44 @@ bool construct_broken_tx(const currency::account_keys& sender_account_keys, cons struct input_generation_context_data { currency::keypair in_ephemeral; + std::vector sorted_outputs; + size_t real_out_index = 0; }; std::vector in_contexts; uint64_t summary_inputs_money = 0; - //fill inputs - BOOST_FOREACH(const currency::tx_source_entry& src_entr, sources) + // fill inputs + for(const currency::tx_source_entry& src_entr : sources) { - if (src_entr.real_output >= src_entr.outputs.size()) - { - LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()=" << src_entr.outputs.size()); - return false; - } + CHECK_AND_ASSERT_MES(src_entr.real_output < src_entr.outputs.size(), false, "real_output index = " << src_entr.real_output << " is bigger than output_keys.size() = " << src_entr.outputs.size()); + + input_generation_context_data& igc = in_contexts.emplace_back(); + igc.sorted_outputs = prepare_outputs_entries_for_key_offsets(src_entr.outputs, src_entr.real_output, igc.real_out_index); summary_inputs_money += src_entr.amount; - //key_derivation recv_derivation; - in_contexts.push_back(input_generation_context_data()); - currency::keypair& in_ephemeral = in_contexts.back().in_ephemeral; crypto::key_image img; - if (!currency::generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img)) + if (!currency::generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, igc.in_ephemeral, img)) return false; //check that derivated key is equal with real output key - if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].stealth_address)) + if (!(igc.in_ephemeral.pub == igc.sorted_outputs[igc.real_out_index].stealth_address)) { LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:" - << epst::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" - << epst::pod_to_hex(src_entr.outputs[src_entr.real_output].stealth_address)); + << epst::pod_to_hex(igc.in_ephemeral.pub) << ENDL << "real output_public_key:" + << epst::pod_to_hex(igc.sorted_outputs[igc.real_out_index].stealth_address)); return false; } - //put key image into tx input + // fill tx input currency::txin_to_key input_to_key; input_to_key.amount = src_entr.amount; input_to_key.k_image = img; - //fill outputs array and use relative offsets - BOOST_FOREACH(const currency::tx_source_entry::output_entry& out_entry, src_entr.outputs) + // fill ring references + for(const currency::tx_source_entry::output_entry& out_entry : igc.sorted_outputs) input_to_key.key_offsets.push_back(out_entry.out_reference); - input_to_key.key_offsets = currency::absolute_output_offsets_to_relative(input_to_key.key_offsets); // TODO @#@# tx.vin.push_back(input_to_key); } @@ -899,11 +896,11 @@ bool construct_broken_tx(const currency::account_keys& sender_account_keys, cons std::stringstream ss_ring_s; size_t i = 0; - BOOST_FOREACH(const currency::tx_source_entry& src_entr, sources) + for(const currency::tx_source_entry& src_entr : sources) { ss_ring_s << "pub_keys:" << ENDL; std::vector keys_ptrs; - BOOST_FOREACH(const currency::tx_source_entry::output_entry& o, src_entr.outputs) + for(const currency::tx_source_entry::output_entry& o : in_contexts[i].sorted_outputs) { keys_ptrs.push_back(&o.stealth_address); ss_ring_s << o.stealth_address << ENDL; @@ -912,10 +909,10 @@ bool construct_broken_tx(const currency::account_keys& sender_account_keys, cons tx.signatures.push_back(currency::NLSAG_sig()); std::vector& sigs = boost::get(tx.signatures.back()).s; sigs.resize(src_entr.outputs.size()); - crypto::generate_ring_signature(tx_prefix_hash, boost::get(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data()); + crypto::generate_ring_signature(tx_prefix_hash, boost::get(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, in_contexts[i].real_out_index, sigs.data()); ss_ring_s << "signatures:" << ENDL; std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL; }); - ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output; + ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << in_contexts[i].real_out_index; i++; } diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 67a87489..e1930227 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -118,7 +118,7 @@ bool test_parse_hardfork_str_mask() { static_assert(ZANO_HARDFORKS_TOTAL >= 5, "this test was made in assumption that this condition holds"); auto v_range = [](size_t a, size_t b) -> std::vector { std::vector r; for(size_t i = a; i <= b; ++i) r.push_back(i); return r; }; - auto v_concat = [](const std::vector& a, const std::vector& b) -> std::vector { std::vector r = a; r.insert(r.end(), b.begin(), b.end()); return r; }; + //auto v_concat = [](const std::vector& a, const std::vector& b) -> std::vector { std::vector r = a; r.insert(r.end(), b.begin(), b.end()); return r; }; const std::vector res_empty; const std::vector res_all_hf = v_range(0, ZANO_HARDFORKS_TOTAL - 1); std::string hf_total_num_str_m_1 = epee::string_tools::num_to_string_fast(ZANO_HARDFORKS_TOTAL - 1); @@ -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_HF(pos_mining_with_decoys, "3"); // alternative blocks and generic chain-switching tests GENERATE_AND_PLAY(gen_chain_switch_pow_pos); diff --git a/tests/core_tests/emission_test.cpp b/tests/core_tests/emission_test.cpp index f5aca21b..035726ca 100644 --- a/tests/core_tests/emission_test.cpp +++ b/tests/core_tests/emission_test.cpp @@ -118,7 +118,7 @@ bool emission_test::c1(currency::core& c, size_t ev_index, const std::vector(pb.m_block.miner_tx.vin[1]).amount; already_generated_coins += gen_coins; CHECK_AND_ASSERT_MES(already_generated_coins == bcs.total_coins(), false, "total coins missmatch: BCS has: " << bcs.total_coins() << ", expected: " << already_generated_coins); diff --git a/tests/core_tests/escrow_wallet_altchain_test.cpp b/tests/core_tests/escrow_wallet_altchain_test.cpp index 3b105cae..a59063c2 100644 --- a/tests/core_tests/escrow_wallet_altchain_test.cpp +++ b/tests/core_tests/escrow_wallet_altchain_test.cpp @@ -312,7 +312,7 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std LOG_PRINT_YELLOW("sub event #" << eam_event_index << " (height " << e.height << "): eam_event_refresh_and_check", LOG_LEVEL_0); LOG_PRINT_GREEN("Alice's wallet is refreshing...", LOG_LEVEL_1); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; bool stub; alice_wlt->scan_tx_pool(stub); size_t blocks_fetched = 0; diff --git a/tests/core_tests/escrow_wallet_common.h b/tests/core_tests/escrow_wallet_common.h index 85264e9b..f084809c 100644 --- a/tests/core_tests/escrow_wallet_common.h +++ b/tests/core_tests/escrow_wallet_common.h @@ -67,7 +67,7 @@ inline bool refresh_wallet_and_check_1_contract_state(const char* wallet_name, s LOG_PRINT_CYAN("Scan tx pool for " << wallet_name << "'s wallet...", LOG_LEVEL_0); wallet->scan_tx_pool(stub_bool); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = wallet->get_contracts(contracts); CHECK_AND_ASSERT_MES(r && contracts.size() == 1, false, "get_contracts() for " << wallet_name << " failed or returned wrong contracts count: " << contracts.size()); CHECK_AND_ASSERT_MES(contracts.begin()->second.state == expected_contract_state, false, wallet_name << " has invalid contract state: " << tools::wallet_public::get_escrow_contract_state_name(contracts.begin()->second.state) @@ -85,7 +85,7 @@ inline bool refresh_wallet_and_check_contract_state(const char* wallet_name, std CHECK_AND_ASSERT_MES(block_to_be_fetched == SIZE_MAX || blocks_fetched == block_to_be_fetched, false, wallet_name << ": incorrect amount of fetched blocks: " << blocks_fetched << ", expected: " << block_to_be_fetched); wallet->scan_tx_pool(stub_bool); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = wallet->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for " << wallet_name << " failed"); for (const auto& c : contracts) @@ -611,7 +611,7 @@ inline bool operator==(const bc_services::contract_private_details& lhs, const b lhs.title == rhs.title; } -inline bool check_contract_state(const tools::wallet2::escrow_contracts_container& contracts, const bc_services::contract_private_details& cpd, tools::wallet_public::escrow_contract_details::contract_state state, const char* party) +inline bool check_contract_state(const tools::escrow_contracts_container& contracts, const bc_services::contract_private_details& cpd, tools::wallet_public::escrow_contract_details::contract_state state, const char* party) { CHECK_AND_ASSERT_MES(contracts.size() == 1, false, party << " has incorrect number of contracts: " << contracts.size()); CHECK_AND_ASSERT_MES(contracts.begin()->second.private_detailes == cpd, false, party << " has invalid contract's private details"); diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index d8fbf387..b4bfaca3 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -126,7 +126,7 @@ bool escrow_wallet_test::prepare_proposal_accepted_test(currency::core& c, const wallet_buyer->refresh(); wallet_seller->refresh(); - tools::wallet2::escrow_contracts_container contracts_buyer, contracts_seller; + tools::escrow_contracts_container contracts_buyer, contracts_seller; wallet_buyer->get_contracts(contracts_buyer); wallet_seller->get_contracts(contracts_seller); @@ -163,7 +163,7 @@ bool escrow_wallet_test::prepare_proposal_accepted_test(currency::core& c, const CHECK_AND_FORCE_ASSERT_MES(contracts_buyer.begin()->second.state == tools::wallet_public::escrow_contract_details_basic::contract_accepted, false, "Incorrect contracts_buyer state"); CHECK_AND_FORCE_ASSERT_MES(contracts_seller.begin()->second.state == tools::wallet_public::escrow_contract_details_basic::contract_accepted, false, "Incorrect contracts_seller state"); - tools::wallet2::multisig_transfer_container ms_buyer, ms_seller; + tools::multisig_transfer_container ms_buyer, ms_seller; wallet_buyer->get_multisig_transfers(ms_buyer); wallet_seller->get_multisig_transfers(ms_seller); CHECK_AND_FORCE_ASSERT_MES(ms_buyer.size() == 1, false, "Incorrect contracts_buyer state"); @@ -195,7 +195,7 @@ bool escrow_wallet_test::exec_test_with_specific_release_type(currency::core& c, expected_state = tools::wallet_public::escrow_contract_details_basic::contract_released_burned; } - tools::wallet2::escrow_contracts_container contracts_buyer, contracts_seller; + tools::escrow_contracts_container contracts_buyer, contracts_seller; wallet_buyer->finish_contract(multisig_id, release_instruction); r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 2); wallet_buyer->refresh(); @@ -232,7 +232,7 @@ bool escrow_wallet_test::exec_test_with_cancel_release_type(currency::core& c, c wallet_miner->transfer(TESTS_DEFAULT_FEE, wallet_buyer->get_account().get_public_address()); r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 10); wallet_buyer->refresh(); - tools::wallet2::escrow_contracts_container contracts_buyer, contracts_seller; + tools::escrow_contracts_container contracts_buyer, contracts_seller; wallet_buyer->request_cancel_contract(multisig_id, TESTS_DEFAULT_FEE, 60 * 60); r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 2); wallet_buyer->refresh(); @@ -643,7 +643,7 @@ bool escrow_incorrect_proposal::check_normal_proposal(currency::core& c, size_t std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); alice_wlt->refresh(); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(contracts.size() == 1, false, "Alice didn't receive escrow proposal"); CHECK_AND_ASSERT_MES(contracts.begin()->second.is_a == false, false, "proposal has wrong is_a"); @@ -682,7 +682,7 @@ bool escrow_incorrect_proposal::check_incorrect_proposal(currency::core& c, size std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); alice_wlt->refresh(); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; alice_wlt->get_contracts(contracts); if (contracts.size() != 0) @@ -780,7 +780,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st uint64_t alice_post_proposal_balance = alice_wlt->balance(); uint64_t alice_post_proposal_balance_expected = alice_start_balance - TESTS_DEFAULT_FEE; CHECK_AND_ASSERT_MES(alice_post_proposal_balance == alice_post_proposal_balance_expected, false, "Incorrect alice_post_proposal_balance: " << print_money(alice_post_proposal_balance) << ", expected: " << print_money(alice_post_proposal_balance_expected)); - std::deque transfers; + std::deque transfers; alice_wlt->get_transfers(transfers); CHECK_AND_ASSERT_MES(transfers.size() == 2 && ( (transfers[0].is_spent() && (transfers[1].m_flags & (WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION))) || @@ -1330,7 +1330,7 @@ bool escrow_incorrect_proposal_acceptance::check_normal_acceptance(currency::cor CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Alice failed"); @@ -1393,7 +1393,7 @@ bool escrow_incorrect_proposal_acceptance::check_incorrect_acceptance(currency:: alice_wlt->dump_trunsfers(ss, false); LOG_PRINT_L0("check_incorrect_acceptance(" << param << "):" << ENDL << "Alice balance: " << print_money(alice_balance) << ", transfers: " << ENDL << ss.str()); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Alice failed"); @@ -1723,7 +1723,7 @@ bool escrow_custom_test::do_custom_test(currency::core& c, size_t ev_index, cons bob_wlt->refresh(); CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_start_balance, 0, INVALID_BALANCE_VAL, 0, 0), false, ""); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = bob_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Bob failed"); CHECK_AND_ASSERT_MES(check_contract_state(contracts, cd.cpd, tools::wallet_public::escrow_contract_details::proposal_sent, "Bob"), false, "wrong contract"); @@ -2121,7 +2121,7 @@ bool escrow_incorrect_cancel_proposal::check_normal_cancel_proposal(currency::co CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Alice failed"); CHECK_AND_ASSERT_MES(contracts.size() == 1, false, "Alice has incorrect number of contracts: " << contracts.size()); @@ -2209,7 +2209,7 @@ bool escrow_incorrect_cancel_proposal::check_incorrect_cancel_proposal_internal( CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Alice failed"); CHECK_AND_ASSERT_MES(contracts.size() == 1, false, "Alice has incorrect number of contracts: " << contracts.size()); @@ -2283,7 +2283,7 @@ bool escrow_proposal_not_enough_money::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(30), 0, MK_TEST_COINS(30), 0, 0), false, ""); - std::deque transfers; + std::deque transfers; alice_wlt->get_transfers(transfers); CHECK_AND_ASSERT_MES(transfers.size() == 1, false, "Incorrect transfers size: " << transfers.size()); @@ -2392,7 +2392,7 @@ bool escrow_cancellation_and_tx_order::c1(currency::core& c, size_t ev_index, co LOG_PRINT_GREEN("\n" "alice_wlt->send_escrow_proposal()", LOG_LEVEL_0); alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_time, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, "", proposal_tx, escrow_template_tx); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Alice failed"); CHECK_AND_ASSERT_MES(contracts.size() == 1, false, "Alice has incorrect number of contracts: " << contracts.size()); @@ -2593,7 +2593,7 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in LOG_PRINT_GREEN("\n" "alice_wlt->send_escrow_proposal()", LOG_LEVEL_0); alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_time, TESTS_DEFAULT_FEE, b_release_fee, "", proposal_tx, escrow_template_tx); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r, false, "get_contracts() for Alice failed"); CHECK_AND_ASSERT_MES(contracts.size() == 1, false, "Alice has incorrect number of contracts: " << contracts.size()); @@ -2843,7 +2843,7 @@ bool escrow_cancellation_acceptance_expiration::c1(currency::core& c, size_t ev_ CHECK_AND_ASSERT_MES(refresh_wallet_and_check_1_contract_state("Alice", alice_wlt, tools::wallet_public::escrow_contract_details::proposal_sent), false, ""); CHECK_AND_ASSERT_MES(refresh_wallet_and_check_1_contract_state("Bob", bob_wlt, tools::wallet_public::escrow_contract_details::proposal_sent), false, ""); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r && contracts.size() == 1, false, "get_contracts() for Alice failed"); crypto::hash contract_id = contracts.begin()->first; @@ -3217,7 +3217,7 @@ bool escrow_balance::c1(currency::core& c, size_t ev_index, const std::vectorcheck(), false, "balance callback check failed, see above"); - tools::wallet2::escrow_contracts_container contracts; + tools::escrow_contracts_container contracts; r = alice_wlt->get_contracts(contracts); CHECK_AND_ASSERT_MES(r && contracts.size() == 1, false, "get_contracts() for Alice failed"); crypto::hash contract_id = contracts.begin()->first; diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index 6a92499d..a186d7bb 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -493,9 +493,9 @@ bool assets_and_explicit_native_coins_in_outs::c2_alice_deploys_asset(currency:: CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", m_alice_initial_balance - TESTS_DEFAULT_FEE, 0, m_alice_initial_balance - TESTS_DEFAULT_FEE, 0, 0), false, ""); // make sure Alice has two UTXO now - tools::wallet2::transfer_container transfers{}; + tools::transfer_container transfers{}; alice_wlt->get_transfers(transfers); - size_t unspent_transfers = std::count_if(transfers.begin(), transfers.end(), [](const tools::wallet2::transfer_details& tr){ return !tr.is_spent(); }); + size_t unspent_transfers = std::count_if(transfers.begin(), transfers.end(), [](const tools::transfer_details& tr){ return !tr.is_spent(); }); CHECK_AND_ASSERT_MES(unspent_transfers == 2, false, "unexpected number of Alice's unspent transfers: " << unspent_transfers); asset_descriptor_base adb{}; @@ -654,7 +654,7 @@ bool asset_depoyment_and_few_zc_utxos::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", m_alice_initial_balance, 0, m_alice_initial_balance, 0, 0), false, ""); // make sure Alice has correct UTXO wallet structure - tools::wallet2::transfer_container transfers{}; + tools::transfer_container transfers{}; alice_wlt->get_transfers(transfers); size_t zc_unspent_outs = 0, unspent_outs = 0; for(auto& td : transfers) diff --git a/tests/core_tests/multisig_wallet_tests.cpp b/tests/core_tests/multisig_wallet_tests.cpp index 1253b6ee..fd327b76 100644 --- a/tests/core_tests/multisig_wallet_tests.cpp +++ b/tests/core_tests/multisig_wallet_tests.cpp @@ -185,7 +185,7 @@ bool multisig_wallet_test::c1(currency::core& c, size_t ev_index, const std::vec wallet_a->refresh(); wallet_b->refresh(); - tools::wallet2::multisig_transfer_container ms_a, ms_b; + tools::multisig_transfer_container ms_a, ms_b; wallet_a->get_multisig_transfers(ms_a); wallet_b->get_multisig_transfers(ms_b); CHECK_AND_ASSERT_MES(ms_a.size() == 1 && ms_b.size() == 1, false, "Multisig failed: ms_a.size() == 1 && ms_b.size() == 1"); @@ -334,7 +334,7 @@ bool multisig_wallet_test_many_dst::c1(currency::core& c, size_t ev_index, const r = check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", amount - TESTS_DEFAULT_FEE); CHECK_AND_ASSERT_MES(r, false, "invalid balance"); - tools::wallet2::multisig_transfer_container mstc; + tools::multisig_transfer_container mstc; alice_wlt->get_multisig_transfers(mstc); CHECK_AND_ASSERT_MES(mstc.empty(), false, "Got invalid multisig transfer"); @@ -446,7 +446,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, false, "Incorrect numbers of blocks fetched"); r = check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", amount5 + TESTS_DEFAULT_FEE); CHECK_AND_ASSERT_MES(r, false, "Invalid wallet balance"); - tools::wallet2::multisig_transfer_container alice_mstc; + tools::multisig_transfer_container alice_mstc; alice_wlt->get_multisig_transfers(alice_mstc); CHECK_AND_ASSERT_MES(alice_mstc.size() == 2 && alice_mstc.count(ms1_hash) == 1 && alice_mstc.count(ms3_hash) == 1, false, "Alice has incorrect multisig transfers"); @@ -456,7 +456,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, false, "Incorrect numbers of blocks fetched"); r = check_balance_via_wallet(*bob_wlt.get(), "bob_wlt", 0); CHECK_AND_ASSERT_MES(r, false, "Invalid wallet balance"); - tools::wallet2::multisig_transfer_container bob_mstc; + tools::multisig_transfer_container bob_mstc; bob_wlt->get_multisig_transfers(bob_mstc); CHECK_AND_ASSERT_MES(bob_mstc.size() == 2 && bob_mstc.count(ms1_hash) == 1 && bob_mstc.count(ms4_hash) == 1, false, "Bob has incorrect multisig transfers"); @@ -466,7 +466,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, false, "Incorrect numbers of blocks fetched"); r = check_balance_via_wallet(*carol_wlt.get(), "carol_wlt", 0); CHECK_AND_ASSERT_MES(r, false, "Invalid wallet balance"); - tools::wallet2::multisig_transfer_container carol_mstc; + tools::multisig_transfer_container carol_mstc; carol_wlt->get_multisig_transfers(carol_mstc); CHECK_AND_ASSERT_MES(carol_mstc.size() == 2 && carol_mstc.count(ms2_hash) == 1 && carol_mstc.count(ms4_hash) == 1, false, "Carol has incorrect multisig transfers"); @@ -476,7 +476,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, false, "Incorrect numbers of blocks fetched"); r = check_balance_via_wallet(*dan_wlt.get(), "dan_wlt", amount6 + TESTS_DEFAULT_FEE); CHECK_AND_ASSERT_MES(r, false, "Invalid wallet balance"); - tools::wallet2::multisig_transfer_container dan_mstc; + tools::multisig_transfer_container dan_mstc; dan_wlt->get_multisig_transfers(dan_mstc); CHECK_AND_ASSERT_MES(dan_mstc.size() == 2 && dan_mstc.count(ms2_hash) == 1 && dan_mstc.count(ms3_hash) == 1, false, "Dan has incorrect multisig transfers"); @@ -2540,7 +2540,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co miner_wlt->refresh(); alice_wlt->refresh(); - tools::wallet2::multisig_transfer_container ms_m, ms_a; + tools::multisig_transfer_container ms_m, ms_a; miner_wlt->get_multisig_transfers(ms_m); alice_wlt->get_multisig_transfers(ms_a); CHECK_AND_ASSERT_MES(ms_m.size() == 1 && ms_a.size() == 1, false, "Multisig failed: ms_m.size() == 1 && ms_a.size() == 1"); @@ -2571,7 +2571,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co LOG_PRINT_YELLOW("%%%%% tx " << get_transaction_hash(tx) << " is spending multisig output " << multisig_id, LOG_LEVEL_0); bool stub; - std::deque transfers; + std::deque transfers; std::vector unconfirmed_transfers; alice_wlt->scan_tx_pool(stub); diff --git a/tests/core_tests/pos_basic_tests.cpp b/tests/core_tests/pos_basic_tests.cpp index 22b40f78..06fbf71a 100644 --- a/tests/core_tests/pos_basic_tests.cpp +++ b/tests/core_tests/pos_basic_tests.cpp @@ -139,3 +139,149 @@ 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); + currency::account_base& dan_acc = m_accounts[DAN_ACC_IDX]; dan_acc.generate(true); dan_acc.set_createtime(ts); // Dan has an auditable wallet + + 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 and Dan + destinations.emplace_back(47 * TESTS_DEFAULT_FEE, dan_acc.get_public_address()); + 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, ""); + + std::shared_ptr dan_wlt = init_playtime_test_wallet(events, c, m_accounts[DAN_ACC_IDX]); + dan_wlt->refresh(); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*dan_wlt, "Dan", 47 * TESTS_DEFAULT_FEE, INVALID_BALANCE_VAL, 47 * TESTS_DEFAULT_FEE), 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(); + + bob_wlt->refresh(); + 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(); + + carol_wlt->refresh(); + 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()); + } + + + // 4. Dan has an auditable wallet that couldn't use mixins, but still he should be able to successfully mine a PoS block (ring size = 1, zero decoys) + top_block_height = c.get_top_block_height(); + + CHECK_AND_ASSERT_MES(dan_wlt->is_auditable(), false, "Dan's wallet is not auditable, which is unexpected"); + + dan_wlt->refresh(); + r = dan_wlt->try_mint_pos(m_accounts[DAN_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() == 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/core_tests/tx_builder.h b/tests/core_tests/tx_builder.h index 22ff3f5c..e373acd3 100644 --- a/tests/core_tests/tx_builder.h +++ b/tests/core_tests/tx_builder.h @@ -37,7 +37,8 @@ struct tx_builder for(const currency::tx_source_entry::output_entry& out_entry : src_entr.outputs) input_to_key.key_offsets.push_back(out_entry.out_reference); - input_to_key.key_offsets = currency::absolute_output_offsets_to_relative(input_to_key.key_offsets); // TODO @#@# + // if the following line fails, consider using prepare_outputs_entries_for_key_offsets() for correct calculation of real out index + CHECK_AND_ASSERT_THROW_MES(absolute_sorted_output_offsets_to_relative_in_place(input_to_key.key_offsets), "absolute_sorted_output_offsets_to_relative_in_place failed"); m_tx.vin.push_back(input_to_key); } } diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index 4db60da5..a767071a 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -144,7 +144,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, tds.amount), false, ""); // check the transfer has been received - std::list payments; + std::list payments; alice_wlt->get_payments(payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 1, false, "Invalid payments count: " << payments.size()); CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(3), false, "Invalid payment"); @@ -254,7 +254,7 @@ bool wallet_rpc_transfer::c1(currency::core& c, size_t ev_index, const std::vect CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, tds.amount), false, ""); // check the transfer has been received - tools::wallet2::transfer_details td = AUTO_VAL_INIT(td); + tools::transfer_details td = AUTO_VAL_INIT(td); CHECK_AND_ASSERT_MES(alice_wlt->get_transfer_info_by_index(0, td), false, ""); CHECK_AND_ASSERT_MES(td.amount() == MK_TEST_COINS(3), false, "Invalid payment"); CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(2, td.tx_hash(), c), false, ""); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 08c113eb..c4ed9c93 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1072,10 +1072,10 @@ bool gen_wallet_payment_id::generate(std::vector& events) cons CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(40 + 5 + 7 - 10 + 13 + 1) - TESTS_DEFAULT_FEE); DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, MK_TEST_COINS(40 + 5 + 7 - 10 + 13 + 1) - TESTS_DEFAULT_FEE)); - std::list payments; + std::list payments; alice_wlt->get_payments(m_payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 3, false, "Invalid payments count"); - payments.sort([](const tools::wallet2::payment_details& lhs, const tools::wallet2::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks + payments.sort([](const tools::payment_details& lhs, const tools::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(5) && payments.front().m_tx_hash == get_transaction_hash(tx_1), false, "Invalid payments #1"); CHECK_AND_ASSERT_MES(payments.back().m_amount == MK_TEST_COINS(13) && payments.back().m_tx_hash == get_transaction_hash(tx_4), false, "Invalid payments #3"); payments.clear(); @@ -1104,7 +1104,7 @@ bool gen_wallet_payment_id::generate(std::vector& events) cons payments.clear(); alice_wlt->get_payments(m_payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 3, false, "Invalid payments count (2)"); - payments.sort([](const tools::wallet2::payment_details& lhs, const tools::wallet2::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks + payments.sort([](const tools::payment_details& lhs, const tools::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(5) && payments.front().m_tx_hash == get_transaction_hash(tx_1), false, "Invalid payments #1"); CHECK_AND_ASSERT_MES(payments.back().m_amount == MK_TEST_COINS(9) && payments.back().m_tx_hash == get_transaction_hash(tx_6), false, "Invalid payments #3"); @@ -1126,10 +1126,10 @@ bool gen_wallet_payment_id::c1(currency::core& c, size_t ev_index, const std::ve if (!check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", MK_TEST_COINS(56) - TESTS_DEFAULT_FEE, 0, 0, 0, 0)) return false; - std::list payments; + std::list payments; alice_wlt->get_payments(m_payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 3, false, "Invalid payments count (4)"); - payments.sort([](const tools::wallet2::payment_details& lhs, const tools::wallet2::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks + payments.sort([](const tools::payment_details& lhs, const tools::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(5), false, "Invalid payments #1"); CHECK_AND_ASSERT_MES(payments.back().m_amount == MK_TEST_COINS(13), false, "Invalid payments #3"); @@ -1157,10 +1157,10 @@ bool gen_wallet_payment_id::c2(currency::core& c, size_t ev_index, const std::ve return false; - std::list payments; + std::list payments; alice_wlt->get_payments(m_payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 3, false, "Invalid payments count (4)"); - payments.sort([](const tools::wallet2::payment_details& lhs, const tools::wallet2::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks + payments.sort([](const tools::payment_details& lhs, const tools::payment_details& rhs) -> bool { return lhs.m_amount < rhs.m_amount; } ); // sort payments by amount to order them for further checks CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(5), false, "Invalid payments #1"); CHECK_AND_ASSERT_MES(payments.back().m_amount == MK_TEST_COINS(9), false, "Invalid payments #3"); @@ -1230,7 +1230,7 @@ bool gen_wallet_oversized_payment_id::c1(currency::core& c, size_t ev_index, con alice_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3 + 1, false, "incorrect number of blocks fetched by Alice's wallet: " << blocks_fetched); - std::list payments; + std::list payments; alice_wlt->get_payments(payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 1, false, "Invalid payments count: " << payments.size()); CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(3), false, "Invalid payment"); @@ -1306,7 +1306,7 @@ bool gen_wallet_transfers_and_outdated_unconfirmed_txs::generate(std::vectorget_transfers(trs); CHECK_AND_ASSERT_MES(trs.size() == 2 && !trs[0].is_spent() && !trs[1].is_spent(), false, "Wrong transfers state"); @@ -1383,7 +1383,7 @@ bool gen_wallet_transfers_and_chain_switch::generate(std::vectorget_transfers(trs); CHECK_AND_ASSERT_MES(trs.size() == 2 && !trs[0].is_spent() && !trs[1].is_spent(), false, "Wrong transfers state"); diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index b6128929..95646b63 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -193,11 +193,11 @@ bool do_send_money_by_fractions(tools::wallet2& w1, tools::wallet2& w2, size_t m } } -uint64_t got_money_in_first_transfers(const tools::wallet2::transfer_container& incoming_transfers, size_t n_transfers) +uint64_t got_money_in_first_transfers(const tools::transfer_container& incoming_transfers, size_t n_transfers) { uint64_t summ = 0; size_t count = 0; - BOOST_FOREACH(const tools::wallet2::transfer_details& td, incoming_transfers) + BOOST_FOREACH(const tools::transfer_details& td, incoming_transfers) { summ += boost::get(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]).amount; if(++count >= n_transfers) @@ -240,7 +240,7 @@ void wait_unlock_money(tools::wallet2& w, flow_test_context& control) std::string get_incoming_transfers_str(tools::wallet2& w) { - tools::wallet2::transfer_container transfers; + tools::transfer_container transfers; w.get_transfers(transfers); uint64_t spent_count = 0; @@ -453,7 +453,7 @@ bool transactions_flow_test( LOG_PRINT_GREEN("Transfers: " << get_incoming_transfers_str(w1), LOG_LEVEL_0); uint64_t transfer_size = TX_DEFAULT_FEE;//amount_to_transfer / transactions_count; - tools::wallet2::transfer_container incoming_transfers; + tools::transfer_container incoming_transfers; size_t prepared_transfers = 0; @@ -469,7 +469,7 @@ bool transactions_flow_test( //lets go! size_t count = 0; prepared_transfers = 0; - BOOST_FOREACH(tools::wallet2::transfer_details& td, incoming_transfers) + BOOST_FOREACH(tools::transfer_details& td, incoming_transfers) { if (td.is_spent()) continue; diff --git a/tests/performance_tests/api_test.cpp b/tests/performance_tests/api_test.cpp new file mode 100644 index 00000000..47fa456e --- /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.decoys_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 diff --git a/utils/build_script_mac_osx.sh b/utils/build_script_mac_osx.sh index c26b8da9..7153fff9 100755 --- a/utils/build_script_mac_osx.sh +++ b/utils/build_script_mac_osx.sh @@ -185,41 +185,11 @@ rm -f Zano.zip /usr/bin/ditto -c -k --keepParent ./Zano.app ./Zano.zip tmpfile="tmptmptmp" -xcrun altool --notarize-app --primary-bundle-id "org.zano.desktop" -u "andrey@zano.org" -p "@keychain:Developer-altool" --file ./Zano.zip > $tmpfile 2>&1 -NOTARIZE_RES=$? -NOTARIZE_OUTPUT=$( cat $tmpfile ) -rm $tmpfile -echo "NOTARIZE_OUTPUT=$NOTARIZE_OUTPUT" -if [ $NOTARIZE_RES -ne 0 ]; then - echo "Notarization failed" - exit 1 -fi - -GUID=$(echo "$NOTARIZE_OUTPUT" | egrep -Ewo '[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}') -if [ ${#GUID} -ne 36 ]; then - echo "Couldn't get correct GUID from the response, got only \"$GUID\"" - exit 1 -fi - - -success=0 - -# check notarization status -for i in {1..10}; do - xcrun altool --notarization-info $GUID -u "andrey@zano.org" -p "@keychain:Developer-altool" > $tmpfile 2>&1 - NOTARIZE_OUTPUT=$( cat $tmpfile ) - rm $tmpfile - NOTARIZATION_LOG_URL=$(echo "$NOTARIZE_OUTPUT" | sed -n "s/.*LogFileURL\: \([[:graph:]]*\).*/\1/p") - if [ ${#NOTARIZATION_LOG_URL} -ge 30 ]; then - success=1 - curl -L $NOTARIZATION_LOG_URL - break - fi - sleep 60 -done - -if [ $success -ne 1 ]; then - echo "Build notarization failed" +#xcrun altool --notarize-app --primary-bundle-id "org.zano.desktop" -u "andrey@zano.org" -p "@keychain:Developer-altool" --file ./Zano.zip > $tmpfile 2>&1 +xcrun notarytool submit --wait --keychain-profile "notarytool-password" ./Zano.zip +RETURN=$? +if [ $RETURN -ne 0 ]; then + echo "Failed to submit for notarization or notarization failed, error code $RETURN" exit 1 fi diff --git a/utils/test_api_files/COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS.json b/utils/test_api_files/COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS.json new file mode 100644 index 00000000..1397a49d --- /dev/null +++ b/utils/test_api_files/COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS.json @@ -0,0 +1 @@ +{"method": "getrandom_outs","params": {"amounts": [80000000000000000],"outs_count": 11, "use_forced_mix_outs": false }} \ No newline at end of file