diff options
-rw-r--r-- | contrib/epee/include/net/abstract_tcp_server2.inl | 9 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 7 | ||||
-rw-r--r-- | src/p2p/net_node.inl | 1 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 19 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.h | 2 | ||||
-rw-r--r-- | src/rpc/core_rpc_server_commands_defs.h | 30 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 56 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.h | 1 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 103 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 23 | ||||
-rw-r--r-- | src/wallet/wallet_errors.h | 5 | ||||
-rw-r--r-- | tests/functional_tests/transactions_flow_test.cpp | 3 |
12 files changed, 237 insertions, 22 deletions
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index b3d4e5fdb..ca9429c91 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -490,7 +490,9 @@ PRAGMA_WARNING_DISABLE_VS(4355) sleep_before_packet(cb, 1, 1); } - epee::critical_region_t<decltype(m_send_que_lock)> send_guard(m_send_que_lock); // *** critical *** + m_send_que_lock.lock(); // *** critical *** + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_send_que_lock.unlock();}); + long int retry=0; const long int retry_limit = 5*4; while (m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) @@ -504,14 +506,15 @@ PRAGMA_WARNING_DISABLE_VS(4355) long int ms = 250 + (rand()%50); _info_c("net/sleep", "Sleeping because QUEUE is FULL, in " << __FUNCTION__ << " for " << ms << " ms before packet_size="<<cb); // XXX debug sleep + m_send_que_lock.unlock(); boost::this_thread::sleep(boost::posix_time::milliseconds( ms ) ); + m_send_que_lock.lock(); _dbg1("sleep for queue: " << ms); if (retry > retry_limit) { - send_guard.unlock(); _erro("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection"); // _dbg1_c("net/sleep", "send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection"); - close(); + shutdown(); return false; } } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 70cbaf0fd..88ecb2dad 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -498,6 +498,7 @@ block Blockchain::pop_block_from_blockchain() } } } + update_next_cumulative_size_limit(); m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id()); return popped_block; @@ -2712,7 +2713,11 @@ leave: // populate various metadata about the block to be stored alongside it. block_size = cumulative_block_size; cumulative_difficulty = current_diffic; - already_generated_coins = already_generated_coins + base_reward; + // In the "tail" state when the minimum subsidy (implemented in get_block_reward) is in effect, the number of + // coins will eventually exceed MONEY_SUPPLY and overflow a uint64. To prevent overflow, cap already_generated_coins + // at MONEY_SUPPLY. already_generated_coins is only used to compute the block subsidy and MONEY_SUPPLY yields a + // subsidy of 0 under the base formula and therefore the minimum subsidy >0 in the tail state. + already_generated_coins = base_reward < (MONEY_SUPPLY-already_generated_coins) ? already_generated_coins + base_reward : MONEY_SUPPLY; if(m_db->height()) cumulative_difficulty += m_db->get_block_cumulative_difficulty(m_db->height() - 1); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 6278db891..0fab40322 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1319,6 +1319,7 @@ namespace nodetool if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id) { LOG_PRINT_CC_L2(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << ip << ":" << port << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id); + m_net_server.get_config_object().close(ping_context.m_connection_id); return; } m_net_server.get_config_object().close(ping_context.m_connection_id); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 9fcb4373b..9e8d1108e 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -166,6 +166,25 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res) + { + CHECK_CORE_BUSY(); + NOTIFY_RESPONSE_CHAIN_ENTRY::request resp; + + resp.start_height = req.start_height; + if(!m_core.find_blockchain_supplement(req.block_ids, resp)) + { + res.status = "Failed"; + return false; + } + res.current_height = resp.total_height; + res.start_height = resp.start_height; + res.m_block_ids = std::move(resp.m_block_ids); + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) { CHECK_CORE_BUSY(); diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 5c3707209..4bed148fe 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -75,6 +75,7 @@ namespace cryptonote BEGIN_URI_MAP2() MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT) MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST) + MAP_URI_AUTO_BIN2("/gethashes.bin", on_get_hashes, COMMAND_RPC_GET_HASHES_FAST) 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) MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS) @@ -115,6 +116,7 @@ namespace cryptonote bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res); bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res); + bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res); bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res); bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res); bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 6067a28b7..392c7501f 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -89,6 +89,36 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; }; + + struct COMMAND_RPC_GET_HASHES_FAST + { + + struct request + { + std::list<crypto::hash> 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 */ + uint64_t start_height; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids) + KV_SERIALIZE(start_height) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list<crypto::hash> m_block_ids; + uint64_t start_height; + uint64_t current_height; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids) + KV_SERIALIZE(start_height) + KV_SERIALIZE(current_height) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- struct COMMAND_RPC_GET_TRANSACTIONS { diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 503db7601..44af55949 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -97,6 +97,7 @@ namespace const command_line::arg_descriptor<bool> arg_testnet = {"testnet", sw::tr("For testnet. Daemon must also be launched with --testnet flag"), false}; const command_line::arg_descriptor<bool> arg_restricted = {"restricted-rpc", sw::tr("Restricts RPC to view-only commands"), false}; const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false}; + const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0}; const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; @@ -1137,6 +1138,22 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } } + if (!m_restore_height) + { + std::string heightstr = command_line::input_line("Restore from specific blockchain height (optional, default 0): "); + if (std::cin.eof()) + return false; + if (heightstr.size()) + { + try { + m_restore_height = boost::lexical_cast<uint64_t>(heightstr); + } + catch (boost::bad_lexical_cast &) { + fail_msg_writer() << tr("bad m_restore_height parameter:") << " " << heightstr; + return false; + } + } + } if (!m_generate_from_view_key.empty()) { // parse address @@ -1307,6 +1324,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet); m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic); m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon); + m_restore_height = command_line::get_arg(vm, arg_restore_height); return true; } @@ -1411,6 +1429,15 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string } m_wallet->init(m_daemon_address); + // for a totally new account, we don't care about older blocks. + if (!m_restore_deterministic_wallet) + { + std::string err; + m_wallet->set_refresh_from_block_height(get_daemon_blockchain_height(err)); + } else if (m_restore_height) + { + m_wallet->set_refresh_from_block_height(m_restore_height); + } // convert rng value to electrum-style word list std::string electrum_words; @@ -1458,6 +1485,7 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string } m_wallet->init(m_daemon_address); + m_wallet->set_refresh_from_block_height(m_restore_height); return true; } @@ -1483,6 +1511,7 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string } m_wallet->init(m_daemon_address); + m_wallet->set_refresh_from_block_height(m_restore_height); return true; } @@ -2212,24 +2241,36 @@ bool simple_wallet::transfer_main(bool new_algorithm, const std::vector<std::str if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1) { uint64_t total_fee = 0; + uint64_t dust_not_in_fee = 0; + uint64_t dust_in_fee = 0; for (size_t n = 0; n < ptx_vector.size(); ++n) { total_fee += ptx_vector[n].fee; + + if (ptx_vector[n].dust_added_to_fee) + dust_in_fee += ptx_vector[n].dust; + else + dust_not_in_fee += ptx_vector[n].dust; } - std::string prompt_str; + std::stringstream prompt; if (ptx_vector.size() > 1) { - prompt_str = (boost::format(tr("Your transaction needs to be split into %llu transactions. " - "This will result in a transaction fee being applied to each transaction, for a total fee of %s. Is this okay? (Y/Yes/N/No)")) % - ((unsigned long long)ptx_vector.size()) % print_money(total_fee)).str(); + prompt << boost::format(tr("Your transaction needs to be split into %llu transactions. " + "This will result in a transaction fee being applied to each transaction, for a total fee of %s")) % + ((unsigned long long)ptx_vector.size()) % print_money(total_fee); } else { - prompt_str = (boost::format(tr("The transaction fee is %s. Is this okay? (Y/Yes/N/No)")) % - print_money(total_fee)).str(); + prompt << boost::format(tr("The transaction fee is %s")) % + print_money(total_fee); } - std::string accepted = command_line::input_line(prompt_str); + if (dust_in_fee != 0) prompt << boost::format(tr(", of which %s is dust from change")) % print_money(dust_in_fee); + if (dust_not_in_fee != 0) prompt << tr(".") << ENDL << boost::format(tr("A total of %s from dust change will be sent to dust address")) + % print_money(dust_not_in_fee); + prompt << tr(".") << ENDL << tr("Is this okay? (Y/Yes/N/No)"); + + std::string accepted = command_line::input_line(prompt.str()); if (std::cin.eof()) return true; if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes") @@ -3163,6 +3204,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_testnet); command_line::add_arg(desc_params, arg_restricted); command_line::add_arg(desc_params, arg_trusted_daemon); + command_line::add_arg(desc_params, arg_restore_height); tools::wallet_rpc_server::init_options(desc_params); po::positional_options_description positional_options; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index e7884155e..b825f71df 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -233,6 +233,7 @@ namespace cryptonote bool m_restore_deterministic_wallet; // recover flag bool m_non_deterministic; // old 2-random generation bool m_trusted_daemon; + uint64_t m_restore_height; // optional std::string m_daemon_address; std::string m_daemon_host; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 078ae7f0c..85ca82920 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -578,6 +578,24 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height, blocks = res.blocks; } //---------------------------------------------------------------------------------------------------- +void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::list<crypto::hash> &hashes) +{ + cryptonote::COMMAND_RPC_GET_HASHES_FAST::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_GET_HASHES_FAST::response res = AUTO_VAL_INIT(res); + req.block_ids = short_chain_history; + + req.start_height = start_height; + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/gethashes.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT); + m_daemon_rpc_mutex.unlock(); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gethashes.bin"); + THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gethashes.bin"); + THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_hashes_error, res.status); + + blocks_start_height = res.start_height; + hashes = res.m_block_ids; +} +//---------------------------------------------------------------------------------------------------- void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote::block_complete_entry> &blocks, uint64_t& blocks_added) { size_t current_index = start_height; @@ -772,6 +790,60 @@ void wallet2::check_pending_txes() } } //---------------------------------------------------------------------------------------------------- +void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history) +{ + std::list<crypto::hash> hashes; + size_t current_index = m_blockchain.size(); + while(current_index < stop_height) + { + pull_hashes(0, blocks_start_height, short_chain_history, hashes); + if (hashes.size() < 3) + return; + if (hashes.size() + current_index < stop_height) { + std::list<crypto::hash>::iterator right; + // drop early 3 off, skipping the genesis block + if (short_chain_history.size() > 3) { + right = short_chain_history.end(); + std::advance(right,-1); + std::list<crypto::hash>::iterator left = right; + std::advance(left, -3); + short_chain_history.erase(left, right); + } + right = hashes.end(); + // prepend 3 more + for (int i = 0; i<3; i++) { + right--; + short_chain_history.push_front(*right); + } + } + current_index = blocks_start_height; + BOOST_FOREACH(auto& bl_id, hashes) + { + if(current_index >= m_blockchain.size()) + { + LOG_PRINT_L2( "Skipped block by height: " << current_index); + m_blockchain.push_back(bl_id); + ++m_local_bc_height; + + if (0 != m_callback) + { // FIXME: this isn't right, but simplewallet just logs that we got a block. + cryptonote::block dummy; + m_callback->on_new_block(current_index, dummy); + } + } + else if(bl_id != m_blockchain[current_index]) + { + //split detected here !!! + return; + } + ++current_index; + if (current_index >= stop_height) + return; + } + } +} + +//---------------------------------------------------------------------------------------------------- void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& received_money) { received_money = false; @@ -786,7 +858,22 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re // pull the first set of blocks get_short_chain_history(short_chain_history); + if (start_height > m_blockchain.size() || m_refresh_from_block_height > m_blockchain.size()) { + if (!start_height) + start_height = m_refresh_from_block_height; + // we can shortcut by only pulling hashes up to the start_height + fast_refresh(start_height, blocks_start_height, short_chain_history); + // regenerate the history now that we've got a full set of hashes + short_chain_history.clear(); + get_short_chain_history(short_chain_history); + start_height = 0; + // and then fall through to regular refresh processing + } + pull_blocks(start_height, blocks_start_height, short_chain_history, blocks); + // always reset start_height to 0 to force short_chain_ history to be used on + // subsequent pulls in this refresh. + start_height = 0; m_run.store(true, std::memory_order_relaxed); while(m_run.load(std::memory_order_relaxed)) @@ -1966,8 +2053,9 @@ void wallet2::commit_tx(pending_tx& ptx) BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers) it->m_spent = true; + //fee includes dust if dust policy specified it. LOG_PRINT_L0("Transaction successfully sent. <" << txid << ">" << ENDL - << "Commission: " << print_money(ptx.fee+ptx.dust) << " (dust: " << print_money(ptx.dust) << ")" << ENDL + << "Commission: " << print_money(ptx.fee) << " (dust sent to dust addr: " << print_money((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL << "Balance: " << print_money(balance()) << ENDL << "Unlocked: " << print_money(unlocked_balance()) << ENDL << "Please, wait for confirmation for your balance to be unlocked."); @@ -2225,10 +2313,17 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent return true; }); THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx); + + + bool dust_sent_elsewhere = (dust_policy.addr_for_dust.m_view_public_key != change_dts.addr.m_view_public_key + || dust_policy.addr_for_dust.m_spend_public_key != change_dts.addr.m_spend_public_key); + + if (dust_policy.add_to_fee || dust_sent_elsewhere) change_dts.amount -= dust; ptx.key_images = key_images; - ptx.fee = fee; - ptx.dust = dust; + ptx.fee = (dust_policy.add_to_fee ? fee+dust : fee); + ptx.dust = ((dust_policy.add_to_fee || dust_sent_elsewhere) ? dust : 0); + ptx.dust_added_to_fee = dust_policy.add_to_fee; ptx.tx = tx; ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; @@ -2393,7 +2488,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(txBlob); - available_for_fee = test_ptx.fee + test_ptx.change_dts.amount; + available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0); LOG_PRINT_L2("Made a " << txBlob.size() << " kB tx, with " << print_money(available_for_fee) << " available for fee (" << print_money(needed_fee) << " needed)"); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 38b5ad40a..e76d7a0aa 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -143,6 +143,7 @@ namespace tools { cryptonote::transaction tx; uint64_t dust, fee; + bool dust_added_to_fee; cryptonote::tx_destination_entry change_dts; std::list<transfer_container::iterator> selected_transfers; std::string key_images; @@ -365,6 +366,12 @@ namespace tools std::string get_wallet_file() const; std::string get_keys_file() const; + + std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon); + std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f); + std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon); + std::vector<size_t> select_available_mixable_outputs(bool trusted_daemon); + private: /*! * \brief Stores wallet information to wallet file. @@ -388,6 +395,8 @@ namespace tools bool is_transfer_unlocked(const transfer_details& td) const; bool clear(); void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::list<cryptonote::block_complete_entry> &blocks); + void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::list<crypto::hash> &hashes); + void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history); void pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::list<cryptonote::block_complete_entry> &prev_blocks, std::list<cryptonote::block_complete_entry> &blocks, bool &error); void process_blocks(uint64_t start_height, const std::list<cryptonote::block_complete_entry> &blocks, uint64_t& blocks_added); uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::list<transfer_container::iterator>& selected_transfers, bool trusted_daemon); @@ -404,10 +413,6 @@ namespace tools uint64_t get_upper_tranaction_size_limit(); void check_pending_txes(); std::vector<uint64_t> get_unspent_amounts_vector(); - std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon); - std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f); - std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon); - std::vector<size_t> select_available_mixable_outputs(bool trusted_daemon); cryptonote::account_base m_account; std::string m_daemon_address; @@ -712,10 +717,16 @@ namespace tools return true; }); THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx); + + bool dust_sent_elsewhere = (dust_policy.addr_for_dust.m_view_public_key != change_dts.addr.m_view_public_key + || dust_policy.addr_for_dust.m_spend_public_key != change_dts.addr.m_spend_public_key); + + if (dust_policy.add_to_fee || dust_sent_elsewhere) change_dts.amount -= dust; ptx.key_images = key_images; - ptx.fee = fee; - ptx.dust = dust; + ptx.fee = (dust_policy.add_to_fee ? fee+dust : fee); + ptx.dust = ((dust_policy.add_to_fee || dust_sent_elsewhere) ? dust : 0); + ptx.dust_added_to_fee = dust_policy.add_to_fee; ptx.tx = tx; ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 3de97f49d..184d8a2a1 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -60,6 +60,7 @@ namespace tools // acc_outs_lookup_error // block_parse_error // get_blocks_error + // get_hashes_error // get_out_indexes_error // tx_parse_error // get_tx_pool_error @@ -107,12 +108,14 @@ namespace tools //---------------------------------------------------------------------------------------------------- const char* const failed_rpc_request_messages[] = { "failed to get blocks", + "failed to get hashes", "failed to get out indices", "failed to get random outs" }; enum failed_rpc_request_message_indices { get_blocks_error_message_index, + get_hashes_error_message_index, get_out_indices_error_message_index, get_random_outs_error_message_index }; @@ -291,6 +294,8 @@ namespace tools //---------------------------------------------------------------------------------------------------- typedef failed_rpc_request<refresh_error, get_blocks_error_message_index> get_blocks_error; //---------------------------------------------------------------------------------------------------- + typedef failed_rpc_request<refresh_error, get_hashes_error_message_index> get_hashes_error; + //---------------------------------------------------------------------------------------------------- typedef failed_rpc_request<refresh_error, get_out_indices_error_message_index> get_out_indices_error; //---------------------------------------------------------------------------------------------------- struct tx_parse_error : public refresh_error diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 159ccfd83..6bf910101 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -85,7 +85,8 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor, try { tools::wallet2::pending_tx ptx; - w1.transfer(dsts, mix_in_factor, 0, TEST_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(TEST_DUST_THRESHOLD), tx, ptx, true); + std::vector<size_t> indices = w1.select_available_outputs([](const tools::wallet2::transfer_details&) { return true; }); + w1.transfer(dsts, mix_in_factor, indices, 0, TEST_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(TEST_DUST_THRESHOLD), tx, ptx, true); w1.commit_tx(ptx); return true; } |