aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/wallet2.cpp80
-rw-r--r--src/wallet/wallet2.h7
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];