diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index c378b5cc..56a5b859 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -2552,7 +2552,7 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_ptr->out_no, false, "internal error: in global outs index, transaction out index=" << out_ptr->out_no << " is greater than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id); - CHECK_AND_ASSERT_MES(amount != 0 || height_upper_limit != 0, false, "height_upper_limit must be nonzero for hidden amounts (amount = 0)"); + //CHECK_AND_ASSERT_MES(amount != 0 || height_upper_limit != 0, false, "height_upper_limit must be nonzero for hidden amounts (amount = 0)"); if (height_upper_limit != 0 && tx_ptr->m_keeper_block_height > height_upper_limit) return false; @@ -2610,6 +2610,14 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU oen.amount_commitment = toz.amount_commitment; oen.concealing_point = toz.concealing_point; oen.blinded_asset_id = toz.blinded_asset_id; // TODO @#@# bad design, too much manual coping, consider redesign -- sowle + if (is_coinbase(tx_ptr->tx)) + { + oen.flags |= RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_COINBASE; + if (is_pos_coinbase(tx_ptr->tx)) + { + oen.flags |= RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_POS_COINBASE; + } + } } VARIANT_SWITCH_END(); @@ -2698,9 +2706,9 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO return true; } //------------------------------------------------------------------ -bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const +bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const { - size_t decoys_count = details.offsets.size(); + size_t decoys_count = details.global_offsets.size(); uint64_t amount = details.amount; uint64_t outs_container_size = m_db_outputs.get_item_size(details.amount); @@ -2727,7 +2735,7 @@ bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RP if (up_index_limit >= decoys_count) { std::set used; - used.insert(details.own_global_index); + //used.insert(details.own_global_index); for (uint64_t j = 0; j != decoys_count || used.size() >= up_index_limit;) { size_t g_index_initial = crypto::rand() % up_index_limit; @@ -2770,117 +2778,27 @@ bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RP } } //------------------------------------------------------------------ -bool blockchain_storage::get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const +bool blockchain_storage::get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const { - std::set used; - used.insert(details.own_global_index); - for (auto offset : details.offsets) + for (auto global_index : details.global_offsets) { - - //perfectly we would need to find transaction's output on the given height, with the given probability - //of being coinbase(coinbase outputs should be included less in decoy selection algorithm) - bool is_coinbase = (crypto::rand() % 101) > req.coinbase_percents ? false : true; - - //TODO: Consider including PoW coinbase to transactions(does it needed?) - - // convert offset to estimated height - uint64_t estimated_h = this->get_current_blockchain_size() - 1 - offset; - //make sure it's after zc hardfork - if (estimated_h < m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]) - { - LOG_ERROR("Wrong estimated offset(" << offset << "), it hits zone before zarcanum hardfork"); - return false; - } - -#define TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN 10 - //try to find output around given H - std::vector selected_global_indexes; - auto process_tx = [&](const crypto::hash& tx_id) { - - auto tx_ptr = m_db_transactions.find(tx_id); - CHECK_AND_ASSERT_THROW_MES(tx_ptr, "internal error: tx_id " << tx_id << " around estimated_h = " << estimated_h << " not found in db"); - //go through tx outputs - for (size_t i = 0; i != tx_ptr->tx.vout.size(); i++) - { - if (tx_ptr->tx.vout[i].type() != typeid(tx_out_zarcanum)) - { - continue; - } - const tx_out_zarcanum& z_out = boost::get(tx_ptr->tx.vout[i]); - - // NOTE: second part of condition (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && ..) might be not accurate - // since the wallet might want to request more inputs then it planning to do mixins. For now let's keep it this way and fix - // it if we see the problems about it. - if (z_out.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || (z_out.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && z_out.mix_attr < details.offsets.size())) - { - continue; - } - - // skip spent outptus - if (tx_ptr->m_spent_flags[i]) - { - continue; - } - - if (used.find(tx_ptr->m_global_output_indexes[i]) != used.end()) - { - continue; - } - - // add output - // note: code that will process selected_global_indes will be revisiting transactions entries to obtain all - // needed data, that should work relatively effective because of on-top-of-db cache keep daya unserialized - selected_global_indexes.push_back(tx_ptr->m_global_output_indexes[i]); - } - - }; - - while (selected_global_indexes.size() < TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN) - { - auto block_ptr = m_db_blocks.get(estimated_h); - if (is_coinbase && is_pos_block(block_ptr->bl) ) - { - process_tx(get_transaction_hash(block_ptr->bl.miner_tx)); - } - else - { - //looking for regular output of regular transactions - for (auto tx_id : block_ptr->bl.tx_hashes) - { - process_tx(tx_id); - } - } - if(estimated_h) - estimated_h--; - else - { - //likely unusual situation when blocks enumerated all way back to genesis - //let's check if we have at least something - if (!selected_global_indexes.size()) - { - //need to regenerate offsets - return false; - } - } - } - //pick up a random output from selected_global_indes - uint64_t global_index = selected_global_indexes[crypto::rand() % selected_global_indexes.size()]; - bool res = add_out_to_get_random_outs(result_outs, details.amount, global_index, details.offsets.size(), req.use_forced_mix_outs, req.height_upper_limit); - CHECK_AND_ASSERT_THROW_MES(res, "Failed to add_out_to_get_random_outs([" << global_index << "]) at postzarcanum era"); - used.insert(global_index); + bool res = add_out_to_get_random_outs(result_outs, details.amount, global_index, this->get_core_runtime_config().hf4_minimum_mixins, false); + if (!res) + { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry{}); + oen.flags = RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_NOT_ALLOWED; + } } + CHECK_AND_ASSERT_THROW_MES(details.global_offsets.size() == result_outs.outs.size(), "details.global_offsets.size() == result_outs.outs.size() check failed"); return true; } //------------------------------------------------------------------ -bool blockchain_storage::get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const +bool blockchain_storage::get_random_outs_for_amounts3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res)const { CRITICAL_REGION_LOCAL(m_read_lock); LOG_PRINT_L3("[get_random_outs_for_amounts] amounts: " << req.amounts.size()); std::map amounts_to_up_index_limit_cache; - uint64_t count_zarcanum_blocks = 0; - if(is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) - count_zarcanum_blocks = this->get_current_blockchain_size() - m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]; for (size_t i = 0; i != req.amounts.size(); i++) @@ -2891,7 +2809,7 @@ bool blockchain_storage::get_random_outs_for_amounts2(const COMMAND_RPC_GET_RAND result_outs.amount = amount; bool r = false; - if (amount == 0 && count_zarcanum_blocks > 20000) + if (amount == 0) { //zarcanum era inputs r = get_target_outs_for_postzarcanum(req, req.amounts[i], result_outs, amounts_to_up_index_limit_cache); @@ -3595,7 +3513,7 @@ bool blockchain_storage::get_est_height_from_date(uint64_t date, uint64_t& res_h return true; } //------------------------------------------------------------------ -bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height, bool need_global_indexes)const +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height)const { CRITICAL_REGION_LOCAL(m_read_lock); blocks_direct_container blocks_direct; @@ -3614,7 +3532,7 @@ bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height, bool request_coinbase_info)const +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height)const { CRITICAL_REGION_LOCAL(m_read_lock); if (!find_blockchain_supplement(qblock_ids, start_height)) @@ -3631,8 +3549,7 @@ bool blockchain_storage::find_blockchain_supplement(const std::list mis; get_transactions_direct(m_db_blocks[i]->bl.tx_hashes, blocks.back().second, mis); CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, block " << get_block_hash(m_db_blocks[i]->bl) << " [" << i << "] contains missing transactions: " << mis); - if(request_coinbase_info) - blocks.back().third = m_db_transactions.find(get_transaction_hash(m_db_blocks[i]->bl.miner_tx)); + blocks.back().third = m_db_transactions.find(get_transaction_hash(m_db_blocks[i]->bl.miner_tx)); } return true; } diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 5bf57ad4..c59bdcd0 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -280,13 +280,13 @@ namespace currency bool get_short_chain_history(std::list& ids)const; bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp)const; bool find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset)const; - bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0, bool need_global_indexes = false)const; - bool find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0, bool request_coinbase_info = false)const; + bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0)const; + bool find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0)const; //bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const; bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const; bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; - bool get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const; + bool get_random_outs_for_amounts3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res)const; bool get_backward_blocks_sizes(size_t from_height, std::vector& sz, size_t count)const; bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs)const; bool get_alias_info(const std::string& alias, extra_alias_entry_base& info)const; @@ -643,8 +643,8 @@ namespace currency bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false, uint64_t height_upper_limit = 0) const; - bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; - bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; + bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; + bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; bool add_block_as_invalid(const block& bl, const crypto::hash& h); bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); size_t find_end_of_allowed_index(uint64_t amount)const; diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index aee33609..487502f4 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -249,8 +249,9 @@ #define BC_OFFERS_CURRENT_OFFERS_SERVICE_ARCHIVE_VER CURRENCY_FORMATION_VERSION + BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 9 #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" -#define WALLET_FILE_SERIALIZATION_VERSION 163 -#define WALLET_FILE_LAST_SUPPORTED_VERSION 163 + +#define WALLET_FILE_SERIALIZATION_VERSION 165 +#define WALLET_FILE_LAST_SUPPORTED_VERSION 165 #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 7eda942c..d45e9704 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -289,7 +289,7 @@ namespace currency } blockchain_storage::blocks_direct_container bs; - if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height, req.need_global_indexes)) + if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height)) { res.status = API_RETURN_CODE_FAIL; return false; @@ -326,7 +326,7 @@ namespace currency } blockchain_storage::blocks_direct_container bs; - if (!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height, req.need_global_indexes)) + if (!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height)) { res.status = API_RETURN_CODE_FAIL; return false; @@ -336,21 +336,15 @@ namespace currency { res.blocks.resize(res.blocks.size()+1); res.blocks.back().block = block_to_blob(b.first->bl); - if (req.need_global_indexes) - { - CHECK_AND_ASSERT_MES(b.third.get(), false, "Internal error on handling COMMAND_RPC_GET_BLOCKS_FAST: b.third is empty, ie coinbase info is not prepared"); - res.blocks.back().coinbase_global_outs = b.third->m_global_output_indexes; - res.blocks.back().tx_global_outs.resize(b.second.size()); - } + CHECK_AND_ASSERT_MES(b.third.get(), false, "Internal error on handling COMMAND_RPC_GET_BLOCKS_FAST: b.third is empty, ie coinbase info is not prepared"); + res.blocks.back().coinbase_global_outs = b.third->m_global_output_indexes; + res.blocks.back().tx_global_outs.resize(b.second.size()); size_t i = 0; BOOST_FOREACH(auto& t, b.second) { res.blocks.back().txs.push_back(tx_to_blob(t->tx)); - if (req.need_global_indexes) - { - res.blocks.back().tx_global_outs[i].v = t->m_global_output_indexes; - } + res.blocks.back().tx_global_outs[i].v = t->m_global_output_indexes; i++; } } @@ -424,11 +418,11 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx) + bool core_rpc_server::on_get_random_outs3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res, connection_context& cntx) { CHECK_CORE_READY(); res.status = API_RETURN_CODE_FAIL; - if (!m_core.get_blockchain_storage().get_random_outs_for_amounts2(req, res)) + if (!m_core.get_blockchain_storage().get_random_outs_for_amounts3(req, res)) { return true; } diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 2c7b47a9..e88f6dbf 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -50,7 +50,7 @@ namespace currency bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx); bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY::response& res, connection_context& cntx); bool on_get_random_outs1(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx); - bool on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx); + bool on_get_random_outs3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res, connection_context& cntx); bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx); bool on_set_maintainers_info(const COMMAND_RPC_SET_MAINTAINERS_INFO::request& req, COMMAND_RPC_SET_MAINTAINERS_INFO::response& res, connection_context& cntx); bool on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx); @@ -112,7 +112,7 @@ namespace currency MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES) MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY) MAP_URI_AUTO_BIN2("/getrandom_outs1.bin", on_get_random_outs1, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) - MAP_URI_AUTO_BIN2("/getrandom_outs2.bin", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2) + MAP_URI_AUTO_BIN2("/getrandom_outs3.bin", on_get_random_outs3, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3) MAP_URI_AUTO_BIN2("/set_maintainers_info.bin", on_set_maintainers_info, COMMAND_RPC_SET_MAINTAINERS_INFO) MAP_URI_AUTO_BIN2("/get_tx_pool.bin", on_get_tx_pool, COMMAND_RPC_GET_TX_POOL) MAP_URI_AUTO_BIN2("/check_keyimages.bin", on_check_keyimages, COMMAND_RPC_CHECK_KEYIMAGES) @@ -146,7 +146,7 @@ namespace currency 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_LEGACY) MAP_JON_RPC ("getrandom_outs1", on_get_random_outs1, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) - MAP_JON_RPC ("getrandom_outs2", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2) + MAP_JON_RPC ("getrandom_outs3", on_get_random_outs3, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3) 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 5da22c9f..9f85c118 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -162,12 +162,10 @@ namespace currency struct request { - bool need_global_indexes; uint64_t minimum_height; std::list block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */ BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(need_global_indexes) KV_SERIALIZE(minimum_height) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids) END_KV_SERIALIZE_MAP() @@ -383,6 +381,11 @@ namespace currency END_KV_SERIALIZE_MAP() }; + +#define RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_COINBASE 0x0000000000000001LL +#define RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_NOT_ALLOWED 0x0000000000000002LL +#define RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_POS_COINBASE 0x0000000000000004LL + #pragma pack (push, 1) struct out_entry { @@ -398,12 +401,13 @@ namespace currency crypto::public_key concealing_point; // premultiplied by 1/8 crypto::public_key amount_commitment; // premultiplied by 1/8 crypto::public_key blinded_asset_id; // premultiplied by 1/8 + uint64_t flags; }; #pragma pack(pop) struct outs_for_amount { - uint64_t amount; + uint64_t amount = 0; std::list outs; BEGIN_KV_SERIALIZE_MAP() @@ -423,18 +427,16 @@ namespace currency }; }; //----------------------------------------------- - struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2 + struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3 { struct offsets_distribution { uint64_t amount; //if amount is 0 then lookup in post-zarcanum zone only, if not 0 then pre-zarcanum only - std::vector offsets; //[i] = height, estimated location where to pickup output of transaction - uint64_t own_global_index; //index to exclude from selection + std::vector global_offsets; //[i] = global_index to pick up BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) - KV_SERIALIZE(offsets) - KV_SERIALIZE(own_global_index) + KV_SERIALIZE(global_offsets) END_KV_SERIALIZE_MAP() }; diff --git a/src/version.h.in b/src/version.h.in index 6bfc64f8..a85f5f41 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 282 +#define PROJECT_VERSION_BUILD_NO 286 #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 ae7ff6ea..4bd94188 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -39,7 +39,6 @@ namespace tools currency::COMMAND_RPC_GET_BLOCKS_FAST::request req; req.block_ids = rqt.block_ids; req.minimum_height = rqt.minimum_height; - req.need_global_indexes = rqt.need_global_indexes; currency::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res); bool r = call_COMMAND_RPC_GET_BLOCKS_FAST(req, res); rsp.status = res.status; @@ -98,9 +97,9 @@ namespace tools return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs1.bin", req, res); } //------------------------------------------------------------------------------------------------------------------------------ - bool default_http_core_proxy::call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res) + bool default_http_core_proxy::call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res) { - return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs2.bin", req, res); + return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs3.bin", req, res); } //------------------------------------------------------------------------------------------------------------------------------ bool default_http_core_proxy::call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res) diff --git a/src/wallet/core_default_rpc_proxy.h b/src/wallet/core_default_rpc_proxy.h index 51a014a5..c44f8d27 100644 --- a/src/wallet/core_default_rpc_proxy.h +++ b/src/wallet/core_default_rpc_proxy.h @@ -37,7 +37,7 @@ namespace tools bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& rqt, currency::COMMAND_RPC_GET_TX_POOL::response& rsp) override; bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& rqt, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& rsp) override; bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& rsp) override; - bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& rsp) override; + bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& rsp) override; bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& rqt, currency::COMMAND_RPC_SEND_RAW_TX::response& rsp) override; bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& rqt, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& rsp) override; bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& rsp) override; diff --git a/src/wallet/core_fast_rpc_proxy.h b/src/wallet/core_fast_rpc_proxy.h index daac69eb..bf8ac62e 100644 --- a/src/wallet/core_fast_rpc_proxy.h +++ b/src/wallet/core_fast_rpc_proxy.h @@ -58,9 +58,9 @@ namespace tools return m_rpc.on_get_random_outs1(req, res, m_cntxt_stub); } //------------------------------------------------------------------------------------------------------------------------------ - bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res) override + bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res) override { - return m_rpc.on_get_random_outs2(req, res, m_cntxt_stub); + return m_rpc.on_get_random_outs3(req, res, m_cntxt_stub); } //------------------------------------------------------------------------------------------------------------------------------ bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res) override diff --git a/src/wallet/core_rpc_proxy.h b/src/wallet/core_rpc_proxy.h index 407e4b49..5a4a25b9 100644 --- a/src/wallet/core_rpc_proxy.h +++ b/src/wallet/core_rpc_proxy.h @@ -36,7 +36,7 @@ namespace tools virtual bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& rqt, currency::COMMAND_RPC_GET_TX_POOL::response& rsp){ return false; } virtual bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& rqt, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& rsp){ return false; } virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& rsp){ return false; } - virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& rsp) { return false; } + virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& rsp) { return false; } virtual bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& rqt, currency::COMMAND_RPC_SEND_RAW_TX::response& rsp){ return false; } virtual bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& rqt, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& rsp){ return false; } virtual bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& rsp){ return false; } diff --git a/src/wallet/decoy_selection.cpp b/src/wallet/decoy_selection.cpp index a75f333d..7a3c8d01 100644 --- a/src/wallet/decoy_selection.cpp +++ b/src/wallet/decoy_selection.cpp @@ -24,9 +24,10 @@ uint64_t scaler::scale(uint64_t h) void decoy_selection_generator::init(uint64_t max_h) { + load_distribution(g_default_distribution, max_h); m_is_initialized = true; - + m_max = max_h; // distribution INCLUDE m_max, count = m_max + 1 } bool decoy_selection_generator::load_distribution_from_file(const char* path) { @@ -66,6 +67,60 @@ std::vector decoy_selection_generator::generate_distribution(uint64_t return res; } + +std::vector decoy_selection_generator::generate_unique_reversed_distribution(uint64_t count) +{ + std::set set_to_extend; + generate_unique_reversed_distribution(count, set_to_extend); + return std::vector(set_to_extend.begin(), set_to_extend.end()); +} + +std::vector decoy_selection_generator::generate_unique_reversed_distribution(uint64_t count, uint64_t preincluded_item) +{ + std::set set_to_extend; + set_to_extend.insert(preincluded_item); + generate_unique_reversed_distribution(count, set_to_extend); + return std::vector(set_to_extend.begin(), set_to_extend.end()); +} + +#define DECOY_SELECTION_GENERATOR_MAX_ITERATIONS 1000000 + +void decoy_selection_generator::generate_unique_reversed_distribution(uint64_t count, std::set& set_to_extend) +{ + if (count + set_to_extend.size() > m_max) + { + throw std::runtime_error("generate_distribution_set with unexpected count"); + } + + size_t attempt_count = 0; + while (set_to_extend.size() != count) + { + attempt_count++; + if (attempt_count > DECOY_SELECTION_GENERATOR_MAX_ITERATIONS) + { + throw std::runtime_error("generate_distribution_set: attempt_count hit DECOY_SELECTION_GENERATOR_MAX_ITERATIONS"); + } + + uint64_t r = 0; + crypto::generate_random_bytes(sizeof(r), &r); + double r_ = map_uint_to_double(r); + auto it = m_distribution_mapping.upper_bound(r_); + if (it == m_distribution_mapping.end()) + { + throw(std::runtime_error(std::string("_r not found in m_distribution_mapping: ") + std::to_string(r_))); + } + uint64_t h = it->second; + if (it != m_distribution_mapping.begin()) + { + uint64_t h_0 = (--it)->second; + crypto::generate_random_bytes(sizeof(r), &r); + h = h_0 + r % (h - h_0) + 1; + } + //scale from nominal to max_h + set_to_extend.insert(m_max - h); + } +} + uint64_t get_distance(const std::vector entries, size_t i) { if (i == 0) @@ -79,7 +134,8 @@ bool decoy_selection_generator::load_distribution(const std::vector derived_distribution; scaler scl; - scl.config_scale(original_distribution.back().h, max_h); + uint64_t adjustment_value = original_distribution[0].h; + scl.config_scale(original_distribution.back().h - adjustment_value, max_h); uint64_t last_scaled_h = 0; std::list last_scaled_array; @@ -87,7 +143,7 @@ bool decoy_selection_generator::load_distribution(const std::vector generate_distribution(uint64_t count); + std::vector generate_unique_reversed_distribution(uint64_t count, uint64_t preincluded_item); + std::vector generate_unique_reversed_distribution(uint64_t count); + void generate_unique_reversed_distribution(uint64_t count, std::set& set_to_extend); bool is_initialized() { return m_is_initialized; } private: bool load_distribution(const std::vector& entries, uint64_t max_h); bool m_is_initialized = false; + uint64_t m_max = 0; std::map m_distribution_mapping; }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 200f5469..0cd49101 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -62,6 +62,10 @@ using namespace currency; #define WALLET_TX_MAX_ALLOWED_FEE (COIN * 100) +#define WALLET_FETCH_RANDOM_OUTS_SIZE 200 + + + #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "wallet" ENABLE_CHANNEL_BY_DEFAULT("wallet") @@ -77,9 +81,10 @@ namespace tools , m_log_prefix("???") , m_watch_only(false) , m_required_decoys_count(CURRENCY_DEFAULT_DECOY_SET_SIZE) + , m_max_allowed_output_amount_for_defragmentation_tx(CURRENCY_BLOCK_REWARD) , 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_decoys_count_for_defragmentation_tx(SIZE_MAX) , m_use_deffered_global_outputs(false) #ifdef DISABLE_TOR , m_disable_tor_relay(true) @@ -504,8 +509,18 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t //PoW block don't have change, so all outs supposed to be marked as "mined" ptc.is_derived_from_coinbase = !ptc.is_pos_coinbase; ptc.height = height; - - + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes, "pglobal_indexes not set"); + if (this->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)) + { + if (pglobal_indexes->size()) + { + //store global index that is under coinage, so we can used in decoy selection algo + if (ptc.height < m_last_known_daemon_height && m_last_known_daemon_height - ptc.height > WALLET_DEFAULT_TX_SPENDABLE_AGE) + { + m_last_zc_global_index = pglobal_indexes->back(); + } + } + } for(auto& in : tx.vin) { @@ -1897,8 +1912,6 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response res = AUTO_VAL_INIT(res); req.minimum_height = get_wallet_minimum_height(); - if (is_auditable()) - req.need_global_indexes = true; if (req.minimum_height > m_height_of_start_sync) m_height_of_start_sync = req.minimum_height; @@ -1951,12 +1964,14 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& res) { size_t current_index = res.start_height; + m_last_known_daemon_height = res.current_height; bool been_matched_block = false; if (res.start_height == 0 && get_blockchain_current_size() == 1 && !res.blocks.empty()) { const currency::block& genesis = res.blocks.front().block_ptr->bl; THROW_IF_TRUE_WALLET_EX(get_block_height(genesis) != 0, error::wallet_internal_error, "first block expected to be genesis"); - process_genesis_if_needed(genesis); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(res.blocks.front().coinbase_ptr, "Unexpected empty coinbase"); + process_genesis_if_needed(genesis, &(res.blocks.front().coinbase_ptr->m_global_output_indexes)); res.blocks.pop_front(); ++current_index; been_matched_block = true; @@ -2479,20 +2494,37 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) //---------------------------------------------------------------------------------------------------- bool wallet2::on_idle() { - scan_unconfirmed_outdate_tx(); + scan_not_compliant_unconfirmed_txs(); return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::scan_unconfirmed_outdate_tx() +bool wallet2::scan_not_compliant_unconfirmed_txs() { uint64_t tx_expiration_ts_median = get_tx_expiration_median(); uint64_t time_limit = m_core_runtime_config.get_core_time() - CURRENCY_MEMPOOL_TX_LIVETIME; for (auto it = m_unconfirmed_txs.begin(); it != m_unconfirmed_txs.end(); ) { - bool tx_outdated = it->second.timestamp < time_limit; - if (tx_outdated || is_tx_expired(it->second.tx, tx_expiration_ts_median)) + bool remove_this_tx = false; + std::stringstream reason_ss; + if (it->second.timestamp < time_limit) { - WLT_LOG_BLUE("removing unconfirmed tx " << it->second.tx_hash << ", reason: " << (tx_outdated ? "outdated" : "expired") << ", tx_expiration_ts_median=" << tx_expiration_ts_median, LOG_LEVEL_0); + remove_this_tx = true; + reason_ss << "outdated, "; + } + if (is_tx_expired(it->second.tx, tx_expiration_ts_median)) + { + remove_this_tx = true; + reason_ss << "expired, "; + } + if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM) && it->second.tx.version < TRANSACTION_VERSION_POST_HF4) + { + remove_this_tx = true; + reason_ss << "not compliant with HF4, "; + } + + if (remove_this_tx) + { + WLT_LOG_BLUE("removing unconfirmed tx " << it->second.tx_hash << ", reason: " << reason_ss.str() << "tx_expiration_ts_median=" << tx_expiration_ts_median, LOG_LEVEL_0); //lookup all used transfer and update flags for (auto i : it->second.selected_indicies) { @@ -2504,15 +2536,18 @@ bool wallet2::scan_unconfirmed_outdate_tx() if (!m_transfers[i].m_spent_height) { uint32_t flags_before = m_transfers[i].m_flags; - m_transfers[i].m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_SPENT); + m_transfers[i].m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_SPENT); // TODO: consider removing other blocking flags (e.g. for escrow tx) -- sowle WLT_LOG_BLUE("mark transfer #" << i << " as unspent, flags: " << flags_before << " -> " << m_transfers[i].m_flags << ", reason: removing unconfirmed tx " << it->second.tx_hash, LOG_LEVEL_0); } } //fire some event m_wcallback->on_transfer_canceled(it->second); m_unconfirmed_txs.erase(it++); - }else + } + else + { it++; + } } //scan marked as spent but don't have height (unconfirmed, and actually not unconfirmed) @@ -2522,16 +2557,11 @@ bool wallet2::scan_unconfirmed_outdate_tx() if (!it->second.has_outgoing_entries()) continue; - for (auto& in : it->second.tx.vin) + for (auto& in_v : it->second.tx.vin) { - if (in.type() == typeid(txin_to_key)) - { - ki_in_unconfirmed.insert(boost::get(in).k_image); - } - else if (in.type() == typeid(txin_zc_input)) - { - ki_in_unconfirmed.insert(boost::get(in).k_image); - } + crypto::key_image ki{}; + if (get_key_image_from_txin_v(in_v, ki)) + ki_in_unconfirmed.insert(ki); } } @@ -4760,6 +4790,7 @@ void wallet2::get_unconfirmed_transfers(std::vector CURRENCY_BLOCK_REWARD) + if (!td.is_native_coin() || td.m_amount > m_max_allowed_output_amount_for_defragmentation_tx) continue; - if (is_transfer_ready_to_go(td, m_decoys_count_for_defragmentation_tx)) + uint64_t fake_outs_count_for_td = m_decoys_count_for_defragmentation_tx == SIZE_MAX ? (td.is_zc() ? m_core_runtime_config.hf4_minimum_mixins : CURRENCY_DEFAULT_DECOY_SET_SIZE) : m_decoys_count_for_defragmentation_tx; + if (is_transfer_ready_to_go(td, fake_outs_count_for_td)) { found_money += td.m_amount; selected_indicies.push_back(i); @@ -5985,7 +6017,7 @@ bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector& sources, std::vector& selected_indicies) @@ -6008,17 +6040,18 @@ bool wallet2::prepare_tx_sources(assets_selection_context& needed_money_map, siz //---------------------------------------------------------------------------------------------------- void wallet2::prefetch_global_indicies_if_needed(const std::vector& selected_indicies) { - std::list> txs; - std::list indices_that_requested_global_indicies; + //std::list> txs; + //std::list indices_that_requested_global_indicies; for (uint64_t i : selected_indicies) { - if (m_transfers[i].m_global_output_index == WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED) - { - indices_that_requested_global_indicies.push_back(i); - txs.push_back(m_transfers[i].m_ptx_wallet_info->m_tx); - } + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, + "m_transfers[" << i << "].m_global_output_index is WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED"); + //indices_that_requested_global_indicies.push_back(i); + //txs.push_back(m_transfers[i].m_ptx_wallet_info->m_tx); + //} } + /* std::vector > outputs_for_all_txs; fetch_tx_global_indixes(txs, outputs_for_all_txs); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(txs.size() == outputs_for_all_txs.size(), "missmatch sizes txs.size() == outputs_for_all_txs.size()"); @@ -6029,7 +6062,7 @@ void wallet2::prefetch_global_indicies_if_needed(const std::vector& se transfer_details& td = m_transfers[*it_indices]; td.m_global_output_index = (*it_ooutputs)[td.m_internal_output_index]; it_ooutputs++; it_indices++; - } + }*/ } //---------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector& sources, const std::vector& selected_indicies) @@ -6049,26 +6082,26 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector= zarcanum_start_from) { //in Zarcanum era - const uint64_t test_scale_size = current_size - 1 - zarcanum_start_from; - zarcanum_decoy_set_generator.init(test_scale_size - 1); + //const uint64_t test_scale_size = current_size - 1 - zarcanum_start_from; + zarcanum_decoy_set_generator.init(m_last_zc_global_index); } bool need_to_request = fake_outputs_count != 0; - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request req = AUTO_VAL_INIT(req); + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request req = AUTO_VAL_INIT(req); 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 req.use_forced_mix_outs = false; // TODO: add this feature to UI later //req.decoys_count = fake_outputs_count + 1; // one more to be able to skip a decoy in case it hits the real output for (uint64_t i: selected_indicies) { - req.amounts.push_back(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution()); - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& rdisttib = req.amounts.back(); + req.amounts.push_back(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution()); + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& rdisttib = req.amounts.back(); auto it = m_transfers.begin() + i; WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->m_ptx_wallet_info->m_tx.vout.size() > it->m_internal_output_index, "m_internal_output_index = " << it->m_internal_output_index << " is greater or equal to outputs count = " << it->m_ptx_wallet_info->m_tx.vout.size()); - rdisttib.own_global_index = it->m_global_output_index; + //rdisttib.own_global_index = it->m_global_output_index; //check if we have Zarcanum era output of pre-Zarcanum if (it->is_zc()) { @@ -6077,15 +6110,14 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vectorm_global_output_index); need_to_request = true; } else { //for prezarcanum era use flat distribution rdisttib.amount = it->m_amount; - rdisttib.offsets.resize(fake_outputs_count, 0); + rdisttib.global_offsets.resize(fake_outputs_count + 1, 0); } } if (need_to_request) @@ -6094,8 +6126,8 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vectorcall_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(req, daemon_resp); - THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs2.bin"); + bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(req, daemon_resp); + THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs3.bin"); if (daemon_resp.status == API_RETURN_CODE_FAIL) { if (attempt_count < 10) @@ -6118,10 +6150,9 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector scanty_outs; THROW_IF_FALSE_WALLET_EX(daemon_resp.outs.size() == req.amounts.size(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count); - //for (COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs : daemon_resp.outs) for(size_t i = 0; i != daemon_resp.outs.size(); i++) { - if (daemon_resp.outs[i].outs.size() != req.amounts[i].offsets.size()) + if (req.amounts[i].amount != 0 && daemon_resp.outs[i].outs.size() != req.amounts[i].global_offsets.size()) { scanty_outs.push_back(daemon_resp.outs[i]); } @@ -6131,6 +6162,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector= fake_outputs_count) break; @@ -6226,6 +6268,72 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector +typename t_obj_container::value_type extract_random_from_container(t_obj_container& container) +{ + auto it = container.begin(); + std::advance(it, (crypto::rand() % container.size())); + typename t_obj_container::value_type obj = *it; + container.erase(it); + return obj; +} +//---------------------------------------------------------------------------------------------------------------- +void wallet2::select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_entry, uint64_t own_g_index) +{ + THROW_IF_FALSE_WALLET_INT_ERR_EX(amount_entry.amount == 0, "Amount is not 0 in zc decoys entry"); + typedef currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; + + //TODO: This strategy would be a subject for continuous refactoring + + //first take all real transactions if ther are some + std::list local_outs; + std::list coinbases; + + while (amount_entry.outs.size() && local_outs.size() != m_core_runtime_config.hf4_minimum_mixins) + { + out_entry entry = extract_random_from_container(amount_entry.outs); + + //skip auditable + if ((entry.flags & (RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_NOT_ALLOWED))) + { + continue; + } + if (entry.flags & (RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_COINBASE)) + { + coinbases.push_back(entry); + continue; + } + // + if (entry.global_amount_index == own_g_index) + { + continue; + } + + local_outs.push_back(entry); + } + + //extend with coin base outs if needed + while (coinbases.size() && local_outs.size() != m_core_runtime_config.hf4_minimum_mixins) + { + out_entry entry = extract_random_from_container(coinbases); + local_outs.push_back(entry); + } + + THROW_IF_FALSE_WALLET_INT_ERR_EX(local_outs.size() == m_core_runtime_config.hf4_minimum_mixins, "Amount is not 0 in zc decoys entry"); + amount_entry.outs = local_outs; +} +//---------------------------------------------------------------------------------------------------------------- +void wallet2::build_distribution_for_input(decoy_selection_generator& zarcanum_decoy_set_generator, std::vector& offsets, uint64_t own_index) +{ + THROW_IF_FALSE_WALLET_INT_ERR_EX(zarcanum_decoy_set_generator.is_initialized(), "zarcanum_decoy_set_generator are not initialized"); + if (m_core_runtime_config.hf4_minimum_mixins) + { + offsets = zarcanum_decoy_set_generator.generate_unique_reversed_distribution(m_last_zc_global_index - 1 > WALLET_FETCH_RANDOM_OUTS_SIZE ? WALLET_FETCH_RANDOM_OUTS_SIZE: m_last_zc_global_index - 1, own_index); + } +} //---------------------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources(crypto::hash multisig_id, std::vector& sources, uint64_t& found_money) { @@ -6757,7 +6865,7 @@ bool wallet2::prepare_free_transfers_cache(uint64_t fake_outputs_count) if (td.m_zc_info_ptr) { //zarcanum out, redefine fake_outputs_count - fake_outputs_count_local = this->is_auditable() ? 0 : CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE; + fake_outputs_count_local = this->is_auditable() ? 0 : m_core_runtime_config.hf4_minimum_mixins; } if (is_transfer_able_to_go(td, fake_outputs_count_local)) { @@ -6862,7 +6970,7 @@ bool wallet2::is_connected_to_net() return (res.synchronized_connections_count) ? true : false; } //---------------------------------------------------------------------------------------------------- -void wallet2::process_genesis_if_needed(const currency::block& genesis) +void wallet2::process_genesis_if_needed(const currency::block& genesis, const std::vector* pglobal_indexes) { if (!m_transfers.empty() || !m_key_images.empty()) return; @@ -6880,7 +6988,7 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis) m_last_bc_timestamp = genesis.timestamp; WLT_LOG_L2("Processing genesis block: " << genesis_hash); - process_new_transaction(genesis.miner_tx, 0, genesis, nullptr); + process_new_transaction(genesis.miner_tx, 0, genesis, pglobal_indexes); } //---------------------------------------------------------------------------------------------------- void wallet2::set_genesis(const crypto::hash& genesis_hash) @@ -7023,7 +7131,7 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money, const crypto::public_key& asset_id, std::vector& final_destinations) { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(found_money >= needed_money, "needed_money==" << needed_money << " < found_money==" << found_money); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(found_money >= needed_money, "found_money = " << print_money_brief(found_money) << " is less than needed_money = " << print_money_brief(needed_money) << ", assed_id: " << asset_id); if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)) { diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 1b0c2892..5ea7a30b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -46,6 +46,7 @@ #include "currency_core/pos_mining.h" #include "view_iface.h" #include "wallet2_base.h" +#include "decoy_selection.h" #define WALLET_DEFAULT_TX_SPENDABLE_AGE CURRENCY_HF4_MANDATORY_MIN_COINAGE #define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1 @@ -147,6 +148,9 @@ namespace tools 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; + uint64_t m_last_zc_global_index = 0; + + //variables that not being serialized std::atomic m_last_bc_timestamp = 0; @@ -154,9 +158,7 @@ namespace tools std::atomic m_last_sync_percent = 0; mutable uint64_t m_current_wallet_file_size = 0; bool m_use_assets_whitelisting = true; - - // variables that should be part of state data object but should not be stored during serialization - mutable std::atomic m_whitelist_updated = false; + //=============================================================== template @@ -220,7 +222,8 @@ namespace tools a & m_rollback_events; a & m_whitelisted_assets; a & m_use_assets_whitelisting; - } + a & m_last_zc_global_index; + } }; @@ -397,6 +400,7 @@ namespace tools void transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx); bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb); + const std::unordered_map& get_own_assets() const { return m_own_asset_descriptors; } 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); @@ -537,7 +541,6 @@ namespace tools 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; - std::string get_balance_str_raw() const; // Returns all payments by given id in unspecified order void get_payments(const std::string& payment_id, std::list& payments, uint64_t min_height = 0) const; @@ -658,14 +661,9 @@ namespace tools bool add_custom_asset_id(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor); bool delete_custom_asset_id(const crypto::public_key& asset_id); - const std::unordered_map& get_local_whitelist() const; - const std::unordered_map& get_global_whitelist() const; - const std::unordered_map& get_own_assets() const; - bool load_whitelisted_tokens_if_not_loaded() const; bool load_whitelisted_tokens() const; - void set_connectivity_options(unsigned int timeout); /* @@ -699,9 +697,6 @@ namespace tools bool encrypt_buffer(const std::string& buff, std::string& res_buff); bool decrypt_buffer(const std::string& buff, std::string& res_buff); bool is_in_hardfork_zone(uint64_t hardfork_index) const; - - //performance inefficient call, suitable only for rare ocasions or super lazy developers - bool proxy_to_daemon(const std::string& uri, const std::string& body, int& response_code, std::string& response_body); construct_tx_param get_default_construct_tx_param(); @@ -761,10 +756,10 @@ private: std::vector get_aliases_for_address(const std::string& addr); bool is_connected_to_net(); bool is_transfer_okay_for_pos(const transfer_details& tr, bool is_zarcanum_hf, uint64_t& stake_unlock_time) const; - bool scan_unconfirmed_outdate_tx(); + bool scan_not_compliant_unconfirmed_txs(); const currency::transaction& get_transaction_by_id(const crypto::hash& tx_hash); void rise_on_transfer2(const wallet_public::wallet_transfer_info& wti); - void process_genesis_if_needed(const currency::block& genesis); + void process_genesis_if_needed(const currency::block& genesis, const std::vector* pglobal_indexes); bool build_escrow_proposal(bc_services::contract_private_details& ecrow_details, uint64_t fee, uint64_t unlock_time, currency::tx_service_attachment& att, std::vector& selected_indicies); bool prepare_tx_sources(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust_threshold, std::vector& sources, std::vector& selected_indicies); bool prepare_tx_sources(size_t fake_outputs_count, std::vector& sources, const std::vector& selected_indicies); @@ -852,6 +847,7 @@ private: uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(uint64_t amount, const std::vector & key_offsets); uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_to_key& intk); uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_zc_input& inzc); + uint8_t out_get_mixin_attr(const currency::tx_out_v& out_t); const crypto::public_key& out_get_pub_key(const currency::tx_out_v& out_t, std::list& htlc_info_list); bool expand_selection_with_zc_input(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector& selected_indexes); @@ -859,6 +855,8 @@ private: void remove_transfer_from_amount_gindex_map(uint64_t tid); uint64_t get_alias_cost(const std::string& alias); detail::split_strategy_id_t get_current_split_strategy(); + void build_distribution_for_input(decoy_selection_generator& zarcanum_decoy_set_generator, std::vector& offsets, uint64_t own_index); + void select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount & amount_entry, uint64_t own_g_index); static void wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); static void wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); @@ -886,6 +884,7 @@ private: bool m_do_rise_transfer; + uint64_t m_max_allowed_output_amount_for_defragmentation_tx; 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; @@ -894,6 +893,7 @@ private: 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; + mutable std::atomic m_whitelist_updated = false; std::shared_ptr m_core_proxy; std::shared_ptr m_wcallback; @@ -911,6 +911,8 @@ private: std::string m_votes_config_path; tools::wallet_public::wallet_vote_config m_votes_config; + uint64_t m_last_known_daemon_height = 0; + //this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions friend class test_generator; }; // class wallet2 diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 59d3f110..1ceff891 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -138,17 +138,17 @@ namespace wallet_public struct wallet_transfer_info { - uint64_t timestamp; - crypto::hash tx_hash; - uint64_t height; //if height == 0 then tx is unconfirmed - uint64_t unlock_time; - uint32_t tx_blob_size; + uint64_t timestamp = 0; + crypto::hash tx_hash = currency::null_hash; + uint64_t height = 0; //if height == 0 then tx is unconfirmed + uint64_t unlock_time = 0; + uint32_t tx_blob_size = 0; std::string payment_id; std::string comment; - bool is_service; - bool is_mixing; - bool is_mining; - uint64_t tx_type; + bool is_service = false; + bool is_mixing = false; + bool is_mining = false; + uint64_t tx_type = 0; employed_tx_entries employed_entries; std::vector service_entries; std::vector remote_addresses; //optional @@ -157,11 +157,11 @@ namespace wallet_public std::vector subtransfers; //not included in streaming serialization - uint64_t fee; - bool show_sender; + uint64_t fee = 0; + bool show_sender = false; std::vector contract; - uint16_t extra_flags; - uint64_t transfer_internal_index; + uint16_t extra_flags = 0; + uint64_t transfer_internal_index = 0; //not included in kv serialization map currency::transaction tx; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index ddd09634..5baf588d 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -38,25 +38,25 @@ POP_VS_WARNINGS catch (const tools::error::daemon_busy& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; \ - er.message = e.what(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY") + e.what(); \ return false; \ } \ catch (const tools::error::not_enough_money& e) \ { \ - er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.error_code(); \ + er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY; \ + er.message = std::string("WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY") + e.error_code(); \ return false; \ } \ catch (const tools::error::wallet_error& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.error_code(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR") + e.error_code(); \ return false; \ } \ catch (const std::exception& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.what(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR") + e.what(); \ return false; \ } \ catch (...) \ diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index f9c0a2a0..d24302e0 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -13,3 +13,4 @@ #define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4 #define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5 #define WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT -6 +#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -7 diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index cce0066b..6b867f7f 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -48,7 +48,7 @@ #define TX_POOL_SCAN_INTERVAL 1 #endif -#define HTTP_PROXY_TIMEOUT 2000 +#define HTTP_PROXY_TIMEOUT 4000 #define HTTP_PROXY_ATTEMPTS_COUNT 1 const command_line::arg_descriptor arg_alloc_win_console ( "alloc-win-console", "Allocates debug console with GUI", false ); diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index f03bf1a2..f7aa0612 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -553,12 +553,16 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain, //skip genesis currency::block_direct_data_entry bdde = AUTO_VAL_INIT(bdde); std::shared_ptr bptr(new block_extended_info()); - bptr->bl = b->b; + bptr->bl = b->b; bdde.block_ptr = bptr; + std::shared_ptr coinbase_tx_ptr(new transaction_chain_entry()); + coinbase_tx_ptr->m_global_output_indexes = get_tx_gindex_from_map(currency::get_transaction_hash(b->b.miner_tx), txs_outs); + bdde.coinbase_ptr = coinbase_tx_ptr; for (auto& tx : b->m_transactions) { std::shared_ptr tx_ptr(new transaction_chain_entry()); tx_ptr->tx = tx; + tx_ptr->m_global_output_indexes = get_tx_gindex_from_map(currency::get_transaction_hash(tx), txs_outs); bdde.txs_ptr.push_back(tx_ptr); } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 690bdef5..65a89226 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -752,6 +752,17 @@ bool shuffle_source_entries(std::vector& sources); // one output will be created for each destination entry and one additional output to add up to old coinbase total amount bool replace_coinbase_in_genesis_block(const std::vector& destinations, test_generator& generator, std::vector& events, currency::block& genesis_block); +template +const std::vector& get_tx_gindex_from_map(const crypto::hash& tx_id, const t_map& id_to_vector) +{ + auto it_global_indexes = id_to_vector.find(tx_id); + if (it_global_indexes == id_to_vector.end()) + { + throw std::runtime_error("TX ID NOT FOUND"); + } + return it_global_indexes->second; +} + //-------------------------------------------------------------------------- template auto do_check_tx_verification_context(const currency::tx_verification_context& tvc, bool tx_added, size_t event_index, const currency::transaction& tx, t_test_class& validator, int) @@ -994,6 +1005,7 @@ namespace crypto { } } + inline uint64_t get_sources_total_amount(const std::vector& s) { uint64_t result = 0; diff --git a/tests/core_tests/wallet_test_core_proxy.cpp b/tests/core_tests/wallet_test_core_proxy.cpp index e303bc8c..db0fd0fc 100644 --- a/tests/core_tests/wallet_test_core_proxy.cpp +++ b/tests/core_tests/wallet_test_core_proxy.cpp @@ -99,20 +99,30 @@ bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_FAST(const currency::CO { auto b = m_blocks[i]; currency::block_complete_entry bce = AUTO_VAL_INIT(bce); - for (auto tx : b->m_transactions) + bce.tx_global_outs.resize(b->m_transactions.size()); + bce.coinbase_global_outs = get_tx_gindex(currency::get_transaction_hash(b->b.miner_tx)); + for (size_t j = 0; j != b->m_transactions.size(); j++) + { + const auto& tx = b->m_transactions[j]; bce.txs.push_back(tx_to_blob(tx)); + bce.tx_global_outs[j].v = get_tx_gindex(currency::get_transaction_hash(tx)); + } bce.block = block_to_blob(b->b); rsp.blocks.push_back(bce); } rsp.current_height = m_blocks.size(); return true; } + +const std::vector& wallet_test_core_proxy::get_tx_gindex(const crypto::hash& tx_id) +{ + return get_tx_gindex_from_map(tx_id, m_txs_outs); +} bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::COMMAND_RPC_GET_BLOCKS_DIRECT::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& rsp) { currency::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req); req.block_ids = rqt.block_ids; req.minimum_height = rqt.minimum_height; - req.need_global_indexes = rqt.need_global_indexes; currency::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res); bool r = this->call_COMMAND_RPC_GET_BLOCKS_FAST(req, res); rsp.status = res.status; diff --git a/tests/core_tests/wallet_test_core_proxy.h b/tests/core_tests/wallet_test_core_proxy.h index 322a7bb3..052a4f70 100644 --- a/tests/core_tests/wallet_test_core_proxy.h +++ b/tests/core_tests/wallet_test_core_proxy.h @@ -26,6 +26,9 @@ struct wallet_test_core_proxy : public tools::i_core_proxy virtual bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res) override; virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override; + const std::vector& get_tx_gindex(const crypto::hash& tx_id); + + test_generator::tx_global_indexes m_txs_outs; test_generator::blockchain_vector m_blocks; test_generator::outputs_index m_oi; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 6d435955..d1a507b1 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -34,11 +34,15 @@ POP_VS_WARNINGS void test_plain_wallet() { - - std::string res = plain_wallet::init("195.201.107.230", "33336", "C:\\Users\\roky\\home\\", 0); + //std::string res = plain_wallet::init("195.201.107.230", "33336", "E:\\tmp\\", 0); + std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home\\", 0); uint64_t instance_id = 0; - res = plain_wallet::open("SEGA_2", "Test2"); + res = plain_wallet::open("test_restored.zan", "111"); + //res = plain_wallet::restore("heart level clear fate sorrow childhood sent fate ceiling party third steel came ask mix neither message already almost vast date glide tumble color okay space", + // "test_restored.zan", "111", ""); + + while(true) { epee::misc_utils::sleep_no_w(2000); @@ -50,16 +54,18 @@ void test_plain_wallet() } - std::string invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}"; - - res = plain_wallet::sync_call("invoke", instance_id, invoke_body); + std::string invoke_body = "{\"method\":\"store\",\"params\":{}}"; + //std::string res1 = plain_wallet::sync_call("invoke", instance_id, invoke_body); - invoke_body = "{\"method\":\"assets_whitelist_get\",\"params\":{}}"; + invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}"; + std::string res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body); - res = plain_wallet::sync_call("invoke", instance_id, invoke_body); + invoke_body = "{\"method\":\"getbalance\",\"params\":{}}"; + std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body); - res = plain_wallet::close_wallet(instance_id); + invoke_body = "{\r\n \"method\": \"transfer\",\r\n \"params\": {\r\n \"destinations\": [\r\n {\r\n \"amount\": \"1000000000000\",\r\n \"address\": \"ZxD9oVwGwW6ULix9Pqttnr7JDpaoLvDVA1KJ9eA9KRxPMRZT5X7WwtU94XH1Z6q6XTMxNbHmbV2xfZ429XxV6fST2DxEg4BQV\",\r\n \"asset_id\": \"cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6\"\r\n }\r\n ],\r\n \"fee\": 10000000000,\r\n \"mixin\": 10,\r\n \"payment_id\": \"\",\r\n \"comment\": \"\",\r\n \"push_payer\": false,\r\n \"hide_receiver\": true\r\n }\r\n}"; + std::string res4 = plain_wallet::sync_call("invoke", instance_id, invoke_body); LOG_PRINT_L0(res); diff --git a/tests/performance_tests/single_tx_test_base.h b/tests/performance_tests/single_tx_test_base.h index 13c4d0ae..a605d624 100644 --- a/tests/performance_tests/single_tx_test_base.h +++ b/tests/performance_tests/single_tx_test_base.h @@ -18,10 +18,10 @@ public: m_bob.generate(); uint64_t block_reward_without_fee = 0; + uint64_t block_reward = 0; if(!construct_miner_tx(0, 0, 0, 2, 0, m_bob.get_keys().account_address, m_bob.get_keys().account_address, m_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, blobdata(), CURRENCY_MINER_TX_MAX_OUTS)) return false; - m_tx_pub_key = get_tx_pub_key_from_extra(m_tx); return true; } diff --git a/tests/unit_tests/decoy_selection.cpp b/tests/unit_tests/decoy_selection.cpp index 47ff298d..19c2d178 100644 --- a/tests/unit_tests/decoy_selection.cpp +++ b/tests/unit_tests/decoy_selection.cpp @@ -10,32 +10,39 @@ TEST(decoy_selection_test, decoy_selection_test) { const uint64_t test_scale_size = 20000; decoy_selection_generator dsg; - dsg.init(test_scale_size - 1); + dsg.init(100); std::map hits; + + + + //std::vector decoys = dsg.generate_distribution(15); + + std::cout << ""; + //std::vector hits(test_scale_size, 0); -// while (true) -// { -// std::vector decoys = dsg.generate_distribution(15); -// for (auto d : decoys) -// { -// hits[d]++; -// } -// -// if (hits[10] > 500) -// break; -// -// } -// std::stringstream ss; -// for (auto it = hits.begin(); it != hits.end(); it++) -// { -// //if (hits[i] != 0) -// { -// ss << it->first << ", " << it->second << ENDL; -// } -// } -// epee::file_io_utils::save_string_to_file("distribution.csv", ss.str()); + while (true) + { + std::vector decoys = dsg.generate_distribution(15); + for (auto d : decoys) + { + hits[d]++; + } + + if (hits[10] > 500) + break; + + } + std::stringstream ss; + for (auto it = hits.begin(); it != hits.end(); it++) + { + if (it->second != 0) + { + ss << it->first << ", " << it->second << std::endl; + } + } + epee::file_io_utils::save_string_to_file("distribution.csv", ss.str()); diff --git a/utils/configure_win64_msvs2022_gui.cmd b/utils/configure_win64_msvs2022_gui.cmd new file mode 100644 index 00000000..b5dcbbf5 --- /dev/null +++ b/utils/configure_win64_msvs2022_gui.cmd @@ -0,0 +1,7 @@ +call configure_local_paths_msvs2022.cmd + +cd .. +@mkdir build_msvc2022_64 +cd build_msvc2022_64 + +cmake -D TESTNET=FALSE -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D OPENSSL_ROOT_DIR="%OPENSSL_ROOT_DIR%" -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2019_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.3" -G "Visual Studio 17 2022" -A x64 -T host=x64 ".." diff --git a/utils/configure_win64_msvs2022_gui_testnet.cmd b/utils/configure_win64_msvs2022_gui_testnet.cmd new file mode 100644 index 00000000..f41547c3 --- /dev/null +++ b/utils/configure_win64_msvs2022_gui_testnet.cmd @@ -0,0 +1,7 @@ +call configure_local_paths_msvs2022.cmd + +cd .. +@mkdir build_msvc2022_64_tn +cd build_msvc2022_64_tn + +cmake -D TESTNET=TRUE -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D OPENSSL_ROOT_DIR="%OPENSSL_ROOT_DIR%" -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2019_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.3" -G "Visual Studio 17 2022" -A x64 -T host=x64 ".." diff --git a/utils/test_api_files/get_alias_by_address.json b/utils/test_api_files/get_alias_by_address.json new file mode 100644 index 00000000..c89f7e97 --- /dev/null +++ b/utils/test_api_files/get_alias_by_address.json @@ -0,0 +1 @@ +{"method": "get_alias_details","params": {"alias": "zoidb"}} \ No newline at end of file diff --git a/utils/test_api_files/get_alias_details.json b/utils/test_api_files/get_alias_details.json index c89f7e97..27871aa7 100644 --- a/utils/test_api_files/get_alias_details.json +++ b/utils/test_api_files/get_alias_details.json @@ -1 +1 @@ -{"method": "get_alias_details","params": {"alias": "zoidb"}} \ No newline at end of file +{"method": "get_alias_details","params": "ZxCjF84feY7GQZ1fdy9r3ZJABwaFjmb2Dd25H5qANWZ2VufpmyNu7ZnShMBDpiw8VW2k1EjPZswgFZnx3v1EYgJ32Rjn64mq9"} \ No newline at end of file