diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/wallet2.cpp | 80 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 7 |
2 files changed, 66 insertions, 21 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8daf26292..cacdc6b3e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -33,6 +33,7 @@ #include <boost/format.hpp> #include <boost/optional/optional.hpp> #include <boost/utility/value_init.hpp> +#include <boost/algorithm/string/join.hpp> #include "include_base_utils.h" using namespace epee; @@ -430,6 +431,20 @@ static void throw_on_rpc_response_error(const boost::optional<std::string> &stat THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, *status); } +std::string strjoin(const std::vector<size_t> &V, const char *sep) +{ + std::stringstream ss; + bool first = true; + for (const auto &v: V) + { + if (!first) + ss << sep; + ss << std::to_string(v); + first = false; + } + return ss.str(); +} + } //namespace namespace tools @@ -643,16 +658,10 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::public_key &pub, } } //---------------------------------------------------------------------------------------------------- -bool wallet2::wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki) -{ - if (!cryptonote::generate_key_image_helper(ack, tx_public_key, real_output_index, in_ephemeral, ki)) - return false; - return true; -} -//---------------------------------------------------------------------------------------------------- void wallet2::scan_output(const cryptonote::account_keys &keys, const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, uint64_t &tx_money_got_in_outs, std::vector<size_t> &outs) { - wallet_generate_key_image_helper(keys, tx_pub_key, i, tx_scan_info.in_ephemeral, tx_scan_info.ki); + bool r = cryptonote::generate_key_image_helper(keys, tx_pub_key, i, tx_scan_info.in_ephemeral, tx_scan_info.ki); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); @@ -1100,7 +1109,10 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids) const size_t current_multiplier = 1; size_t sz = m_blockchain.size() - m_blockchain.offset(); if(!sz) + { + ids.push_back(m_blockchain.genesis()); return; + } size_t current_back_offset = 1; bool base_included = false; while(current_back_offset < sz) @@ -1205,6 +1217,7 @@ void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote:: size_t tx_o_indices_idx = 0; THROW_WALLET_EXCEPTION_IF(blocks.size() != o_indices.size(), error::wallet_internal_error, "size mismatch"); + THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::wallet_internal_error, "Index out of bounds of hashchain"); tools::threadpool& tpool = tools::threadpool::getInstance(); int threads = tpool.get_max_concurrency(); @@ -1920,6 +1933,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p value2.SetInt(m_confirm_backlog ? 1 :0); json.AddMember("confirm_backlog", value2, json.GetAllocator()); + value2.SetUint(m_confirm_backlog_threshold); + json.AddMember("confirm_backlog_threshold", value2, json.GetAllocator()); + value2.SetInt(m_testnet ? 1 :0); json.AddMember("testnet", value2, json.GetAllocator()); @@ -1995,6 +2011,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa m_min_output_value = 0; m_merge_destinations = false; m_confirm_backlog = true; + m_confirm_backlog_threshold = 0; } else { @@ -2067,6 +2084,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa m_merge_destinations = field_merge_destinations; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_backlog, int, Int, false, true); m_confirm_backlog = field_confirm_backlog; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_backlog_threshold, uint32_t, Uint, false, 0); + m_confirm_backlog_threshold = field_confirm_backlog_threshold; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet); // Wallet is being opened with testnet flag, but is saved as a mainnet wallet THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet"); @@ -2547,7 +2566,30 @@ void wallet2::load(const std::string& wallet_, const std::string& password) void wallet2::trim_hashchain() { uint64_t height = m_checkpoints.get_max_height(); - if (height > 0) + if (!m_blockchain.empty() && m_blockchain.size() == m_blockchain.offset()) + { + MINFO("Fixing empty hashchain"); + epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request> req = AUTO_VAL_INIT(req); + epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response, std::string> res = AUTO_VAL_INIT(res); + m_daemon_rpc_mutex.lock(); + req.jsonrpc = "2.0"; + req.id = epee::serialization::storage_entry(0); + req.method = "getblockheaderbyheight"; + req.params.height = m_blockchain.size() - 1; + bool r = net_utils::invoke_http_json("/json_rpc", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + if (r && res.result.status == CORE_RPC_STATUS_OK) + { + crypto::hash hash; + epee::string_tools::hex_to_pod(res.result.block_header.hash, hash); + m_blockchain.refill(hash); + } + else + { + MERROR("Failed to request block header from daemon, hash chain may be unable to sync till the wallet is loaded with a usable daemon"); + } + } + if (height > 0 && m_blockchain.size() > height) { --height; MDEBUG("trimming to " << height << ", offset " << m_blockchain.offset()); @@ -3292,7 +3334,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f signed_tx_set signed_txes; for (size_t n = 0; n < exported_txs.txes.size(); ++n) { - const tools::wallet2::tx_construction_data &sd = exported_txs.txes[n]; + tools::wallet2::tx_construction_data &sd = exported_txs.txes[n]; LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size()); signed_txes.ptx.push_back(pending_tx()); tools::wallet2::pending_tx &ptx = signed_txes.ptx.back(); @@ -4331,7 +4373,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp } else { - THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error, "original_output_index too large"); + THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error, + std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size())); if (original_output_index == dsts.size()) dsts.push_back(tx_destination_entry(0,addr)); THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &addr, sizeof(addr)), error::wallet_internal_error, "Mismatched destination address"); @@ -4430,12 +4473,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp TX &tx = txes.back(); LOG_PRINT_L2("Start of loop with " << unused_transfers_indices.size() << " " << unused_dust_indices.size()); - LOG_PRINT_L2("unused_transfers_indices:"); - for (auto t: unused_transfers_indices) - LOG_PRINT_L2(" " << t); - LOG_PRINT_L2("unused_dust_indices:"); - for (auto t: unused_dust_indices) - LOG_PRINT_L2(" " << t); + LOG_PRINT_L2("unused_transfers_indices: " << strjoin(unused_transfers_indices, " ")); + LOG_PRINT_L2("unused_dust_indices:" << strjoin(unused_dust_indices, " ")); LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? -1 : dsts[0].amount)); LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct); @@ -4609,6 +4648,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp { LOG_PRINT_L2("We have more to pay, starting another tx"); txes.push_back(TX()); + original_output_index = 0; } } } @@ -5222,7 +5262,8 @@ std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key // generate ephemeral secret key crypto::key_image ki; cryptonote::keypair in_ephemeral; - cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, td.m_internal_output_index, in_ephemeral, ki); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, td.m_internal_output_index, in_ephemeral, ki); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && ki != td.m_key_image, error::wallet_internal_error, "key_image generated not matched with cached key image"); @@ -5618,7 +5659,8 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail "Transaction extra has unsupported format at index " + boost::lexical_cast<std::string>(i)); crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td); - cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, td.m_internal_output_index, in_ephemeral, td.m_key_image); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, td.m_internal_output_index, in_ephemeral, td.m_key_image); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); td.m_key_image_known = true; THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i)); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 83863ca54..e31ad5dc8 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -108,7 +108,8 @@ namespace tools void crop(size_t height) { m_blockchain.resize(height - m_offset); } void clear() { m_offset = 0; m_blockchain.clear(); } bool empty() const { return m_blockchain.empty() && m_offset == 0; } - void trim(size_t height) { while (height > m_offset && !m_blockchain.empty()) { m_blockchain.pop_front(); ++m_offset; } m_blockchain.shrink_to_fit(); } + void trim(size_t height) { while (height > m_offset+1 && m_blockchain.size() > 1) { m_blockchain.pop_front(); ++m_offset; } m_blockchain.shrink_to_fit(); } + void refill(const crypto::hash &hash) { m_blockchain.push_back(hash); --m_offset; } template <class t_archive> inline void serialize(t_archive &a, const unsigned int ver) @@ -599,6 +600,8 @@ namespace tools bool merge_destinations() const { return m_merge_destinations; } bool confirm_backlog() const { return m_confirm_backlog; } void confirm_backlog(bool always) { m_confirm_backlog = always; } + void set_confirm_backlog_threshold(uint32_t threshold) { m_confirm_backlog_threshold = threshold; }; + uint32_t get_confirm_backlog_threshold() const { return m_confirm_backlog_threshold; }; bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const; @@ -718,7 +721,6 @@ namespace tools void set_spent(size_t idx, uint64_t height); void set_unspent(size_t idx); void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count); - bool wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki); crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const; @@ -772,6 +774,7 @@ namespace tools uint64_t m_min_output_value; bool m_merge_destinations; bool m_confirm_backlog; + uint32_t m_confirm_backlog_threshold; bool m_is_initialized; NodeRPCProxy m_node_rpc_proxy; std::unordered_set<crypto::hash> m_scanned_pool_txs[2]; |