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/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 6ccb07aa..354e765a 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -2808,6 +2808,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].vote_1++; + else + summary[v.first].vote_0++; + } + } + for (const auto s_entry : summary) + { + r.votes.push_back(s_entry.second); + r.votes.back().proposal_name = s_entry.first; + } + + return true; +} +//------------------------------------------------------------------ std::string blockchain_storage::get_blockchain_string(uint64_t start_index, uint64_t end_index) const { std::stringstream ss; diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 01a95f52..113cff0d 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -451,6 +451,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 8a487003..eaa34c47 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -154,6 +154,28 @@ namespace currency transactions_map onboard_transactions; }; + struct vote_on_proposal + { + std::string proposal_name; + uint64_t vote_1; + uint64_t vote_0; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(proposal_name) + KV_SERIALIZE(vote_1) + KV_SERIALIZE(vote_0) + 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() + }; } \ No newline at end of file diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 18e38c67..7b5aa9c8 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -214,6 +214,7 @@ #define GUI_INTERNAL_CONFIG2 "gui_internal_config.json" #define GUI_IPC_MESSAGE_CHANNEL_NAME CURRENCY_NAME_BASE "_message_que" +#define CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME "voting_config.json" #define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3 diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 7019ce41..2a1b32c0 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1615,6 +1615,35 @@ namespace currency return timestamp; } //--------------------------------------------------------------- + bool parse_vote(const std::string& json_, std::list>& votes) + { + //do preliminary check of text if it looks like json + std::string::size_type pos = json_.find('{'); + if (pos == std::string::npos) + return false; + std::string json = json_.substr(pos); + + epee::serialization::portable_storage ps; + bool rs = ps.load_from_json(json); + if (!rs) + return false; + + + + auto cb = [&](const std::string& name, const epee::serialization::storage_entry& entry) { + if (entry.type() == typeid(uint64_t)) + { + bool vote = boost::get(entry) ? true : false; + votes.push_back(std::make_pair(epee::string_encoding::toupper(name), vote)); + } + return true; + }; + + ps.enum_entries(nullptr, cb); + return true; + + } + //--------------------------------------------------------------- bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed /* = nullptr */) { #define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, msg << ", ms input index: " << ms_input_index << ", tx: " << get_transaction_hash(tx) << ", source tx: " << get_transaction_hash(source_tx)) diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 725b39e1..e8ecadcb 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -362,7 +362,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); template typename std::conditional::value, const std::vector, std::vector >::type& get_txin_etc_options(t_txin_v& in) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 8d0e5858..0337952e 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -631,6 +631,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_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details)) diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 590b1151..bcbe748d 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -85,6 +85,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_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); @@ -150,6 +151,7 @@ namespace currency MAP_JON_RPC ("get_pool_txs_brief_details", on_get_pool_txs_brief_details, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS) MAP_JON_RPC ("get_all_pool_tx_list", on_get_all_pool_tx_list, COMMAND_RPC_GET_ALL_POOL_TX_LIST) MAP_JON_RPC ("get_pool_info", on_get_pool_info, COMMAND_RPC_GET_POOL_INFO) + MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES) MAP_JON_RPC_WE("get_main_block_details", on_get_main_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 3edc5c57..5fb88872 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -83,6 +83,34 @@ 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 COMMAND_RPC_GET_HEIGHT { struct request diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index d2571d62..e4567006 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -58,6 +58,7 @@ namespace const command_line::arg_descriptor arg_addr_to_compare ( "addr-to-compare", ""); 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", ""); @@ -413,6 +414,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() @@ -433,18 +435,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(); 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) { @@ -465,6 +470,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 { @@ -473,6 +481,7 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st // auditable watch-only aka tracking wallet m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_tracking_seed, true, ""); message_writer(epee::log_space::console_color_white, true) << "Tracking wallet restored: " << m_wallet->get_account().get_public_address_str(); + display_vote_info(); } else { @@ -509,11 +518,27 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st return true; } //---------------------------------------------------------------------------------------------------- + +void simple_wallet::display_vote_info() +{ + const wallet_vote_config& votes = m_wallet->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) + { + message_writer(epee::log_space::console_color_magenta, true) << "\t\t" << e.proposal_id << "\t\t" << (e.vote?"1":"0") << "\t\t("<< e.h_start << " - " << e.h_end <<")"; + } + } +} 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) { @@ -521,6 +546,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(); break; } diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 03b428c3..84348e7f 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -96,6 +96,7 @@ namespace currency uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(); + void display_vote_info(); //----------------- i_wallet2_callback --------------------- virtual void on_new_block(uint64_t height, const currency::block& block) override; @@ -172,6 +173,7 @@ namespace currency bool m_offline_mode; bool m_disable_tor; std::string m_restore_wallet; + std::string m_voting_config_file; epee::console_handlers_binder m_cmd_binder; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7b7ffc09..8c112c3d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -67,7 +67,8 @@ namespace tools m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE), m_current_wallet_file_size(0), m_use_deffered_global_outputs(false), - m_disable_tor_relay(false) + m_disable_tor_relay(false), + m_votes_config_path(tools::get_default_data_dir() + "/" + CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME) { m_core_runtime_config = currency::get_default_core_runtime_config(); } @@ -171,7 +172,7 @@ std::shared_ptr wallet2::transform_value_to_pt //---------------------------------------------------------------------------------------------------- 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(); } @@ -2650,6 +2651,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(); @@ -2720,6 +2734,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) ); WLT_LOG_L1("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); + load_votes_config(); 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() << ")"); @@ -3599,7 +3614,30 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& { return build_minted_block(req, rsp, m_account.get_public_address(), new_block_expected_height); } - +//------------------------------------------------------------------ +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++; + } + } + if (!entries_voted) + extra_text = ""; + return extra_text; +} +//------------------------------------------------------------------ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& req, const currency::COMMAND_RPC_SCAN_POS::response& rsp, const currency::account_public_address& miner_address, @@ -3617,7 +3655,7 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& tmpl_req.pos_block = true; tmpl_req.pos_amount = req.pos_entries[rsp.index].amount; tmpl_req.pos_index = req.pos_entries[rsp.index].index; - tmpl_req.extra_text = m_miner_text_info; + tmpl_req.extra_text = get_extra_text_for_block(new_block_expected_height); // m_miner_text_info; tmpl_req.stake_unlock_time = req.pos_entries[rsp.index].stake_unlock_time; // mark stake source as spent and make sure it will be restored in case of error diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index b8ecac13..3ff2a73a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -541,8 +541,7 @@ namespace tools void update_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, const bc_services::offer_details_ex& od, currency::transaction& res_tx); void request_alias_registration(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward, const crypto::secret_key& authority_key = currency::null_skey); void request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward); - bool check_available_sources(std::list& amounts); - + bool check_available_sources(std::list& amounts); bool set_core_proxy(const std::shared_ptr& proxy); void set_pos_mint_packing_size(uint64_t new_size); @@ -817,6 +816,7 @@ namespace tools bool get_pos_entries(currency::COMMAND_RPC_SCAN_POS::request& req); bool build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& req, const currency::COMMAND_RPC_SCAN_POS::response& rsp, uint64_t new_block_expected_height = UINT64_MAX); bool build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& req, const currency::COMMAND_RPC_SCAN_POS::response& rsp, const currency::account_public_address& miner_address, uint64_t new_block_expected_height = UINT64_MAX); + 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; @@ -879,6 +879,9 @@ namespace tools void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin, currency::transaction& result_tx); 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 wallet_vote_config& get_current_votes() { return m_votes_config; } private: // -------- t_transport_state_notifier ------------------------------------------------ @@ -958,10 +961,9 @@ private: bool handle_cancel_proposal(wallet_public::wallet_transfer_info& wti, const bc_services::escrow_cancel_templates_body& ectb, const std::vector& decrypted_attach); bool handle_expiration_list(uint64_t tx_expiration_ts_median); void handle_contract_expirations(uint64_t tx_expiration_ts_median); - 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(); const construct_tx_param& get_default_construct_tx_param(); @@ -1073,6 +1075,9 @@ private: mutable uint64_t m_current_wallet_file_size; bool m_use_deffered_global_outputs; bool m_disable_tor_relay; + + std::string m_votes_config_path; + wallet_vote_config m_votes_config; //this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions friend class test_generator; diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index bde9d9f4..141f6e8f 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -1147,6 +1147,34 @@ 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() + }; + + inline std::string get_escrow_contract_state_name(uint32_t state) { switch (state) diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 0b20459a..8b3bd2aa 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -956,6 +956,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) @@ -970,6 +973,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; @@ -1061,6 +1065,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) @@ -1167,6 +1172,7 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std: { std::shared_ptr w(new tools::wallet2()); w->set_use_deffered_global_outputs(m_use_deffered_global_outputs); + w->set_votes_config_path(m_data_dir + "/" + CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME); owr.wallet_id = m_wallet_id_counter++; w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); if (m_remote_node_mode) diff --git a/tests/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