aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp6
-rw-r--r--src/wallet/api/wallet_manager.cpp36
-rw-r--r--src/wallet/api/wallet_manager.h4
-rw-r--r--src/wallet/wallet2.cpp156
-rw-r--r--src/wallet/wallet2.h85
-rw-r--r--src/wallet/wallet2_api.h6
6 files changed, 161 insertions, 132 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 3a4493ec3..5caa52257 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1010,9 +1010,6 @@ void WalletImpl::doRefresh()
// Syncing daemon and refreshing wallet simultaneously is very resource intensive.
// Disable refresh if wallet is disconnected or daemon isn't synced.
if (daemonSynced()) {
- // Use fast refresh for new wallets
- if (isNewWallet())
- m_wallet->set_refresh_from_block_height(daemonBlockChainHeight());
m_wallet->refresh();
if (!m_synchronized) {
m_synchronized = true;
@@ -1079,7 +1076,8 @@ void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction
m_wallet->init(daemon_address, upper_transaction_size_limit);
// in case new wallet, this will force fast-refresh (pulling hashes instead of blocks)
- if (isNewWallet()) {
+ // If daemon isn't synced a calculated block height will be used instead
+ if (isNewWallet() && daemonSynced()) {
m_wallet->set_refresh_from_block_height(daemonBlockChainHeight());
}
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 4ee5ab8df..6b48caf1d 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -32,6 +32,7 @@
#include "wallet_manager.h"
#include "wallet.h"
#include "common_defines.h"
+#include "common/dns_utils.h"
#include "net/http_client.h"
#include <boost/filesystem.hpp>
@@ -137,7 +138,7 @@ void WalletManagerImpl::setDaemonAddress(const std::string &address)
m_daemonAddress = address;
}
-bool WalletManagerImpl::connected(uint32_t *version = NULL) const
+bool WalletManagerImpl::connected(uint32_t *version) const
{
epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_VERSION::request> req_t = AUTO_VAL_INIT(req_t);
epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_VERSION::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
@@ -352,9 +353,40 @@ double WalletManagerImpl::miningHashRate() const
return mres.speed;
}
+void WalletManagerImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height) const
+{
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_HARD_FORK_INFO::request> req_t = AUTO_VAL_INIT(req_t);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_HARD_FORK_INFO::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
+
+ version = 0;
+ earliest_height = 0;
+
+ epee::net_utils::http::http_simple_client http_client;
+ req_t.jsonrpc = "2.0";
+ req_t.id = epee::serialization::storage_entry(0);
+ req_t.method = "hard_fork_info";
+ req_t.params.version = 0;
+ bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/json_rpc", req_t, resp_t, http_client);
+ if (!r || resp_t.result.status != CORE_RPC_STATUS_OK)
+ return;
+ version = resp_t.result.version;
+ earliest_height = resp_t.result.earliest_height;
+}
+
+uint64_t WalletManagerImpl::blockTarget() const
+{
+ cryptonote::COMMAND_RPC_GET_INFO::request ireq;
+ cryptonote::COMMAND_RPC_GET_INFO::response ires;
+
+ epee::net_utils::http::http_simple_client http_client;
+ if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client))
+ return 0;
+ return ires.target;
+}
+
std::string WalletManagerImpl::resolveOpenAlias(const std::string &address, bool &dnssec_valid) const
{
- std::vector<std::string> addresses = tools::wallet2::addresses_from_url(address, dnssec_valid);
+ std::vector<std::string> addresses = tools::dns_utils::addresses_from_url(address, dnssec_valid);
if (addresses.empty())
return "";
return addresses.front();
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 214afc3fa..01752f69b 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -46,12 +46,14 @@ public:
std::vector<std::string> findWallets(const std::string &path);
std::string errorString() const;
void setDaemonAddress(const std::string &address);
- bool connected(uint32_t *version) const;
+ bool connected(uint32_t *version = NULL) const;
bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const;
uint64_t blockchainHeight() const;
uint64_t blockchainTargetHeight() const;
uint64_t networkDifficulty() const;
double miningHashRate() const;
+ void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const;
+ uint64_t blockTarget() const;
std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const;
private:
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 221dd8e0b..1550787e5 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -51,7 +51,6 @@ using namespace epee;
#include "cryptonote_protocol/blobdatatype.h"
#include "mnemonics/electrum-words.h"
#include "common/i18n.h"
-#include "common/dns_utils.h"
#include "common/util.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
@@ -77,8 +76,8 @@ using namespace cryptonote;
// arbitrary, used to generate different hashes from the same input
#define CHACHA8_KEY_TAIL 0x8c
-#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\002"
-#define SIGNED_TX_PREFIX "Monero signed tx set\002"
+#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003"
+#define SIGNED_TX_PREFIX "Monero signed tx set\003"
#define RECENT_OUTPUT_RATIO (0.25) // 25% of outputs are from the recent zone
#define RECENT_OUTPUT_ZONE (5 * 86400) // last 5 days are the recent zone
@@ -1613,6 +1612,9 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
// and then fall through to regular refresh processing
}
+ // If stop() is called during fast refresh we don't need to continue
+ if(!m_run.load(std::memory_order_relaxed))
+ return;
pull_blocks(start_height, blocks_start_height, short_chain_history, blocks, o_indices);
// always reset start_height to 0 to force short_chain_ history to be used on
// subsequent pulls in this refresh.
@@ -1632,7 +1634,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
process_blocks(blocks_start_height, blocks, o_indices, added_blocks);
blocks_fetched += added_blocks;
pull_thread.join();
- if(!added_blocks)
+ if(blocks_start_height == next_blocks_start_height)
break;
// switch to the new blocks from the daemon
@@ -1668,7 +1670,9 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
try
{
- update_pool_state();
+ // If stop() is called we don't need to check pending transactions
+ if(m_run.load(std::memory_order_relaxed))
+ update_pool_state();
}
catch (...)
{
@@ -2139,7 +2143,7 @@ void wallet2::rewrite(const std::string& wallet_name, const std::string& passwor
prepare_file_names(wallet_name);
boost::system::error_code ignored_ec;
THROW_WALLET_EXCEPTION_IF(!boost::filesystem::exists(m_keys_file, ignored_ec), error::file_not_found, m_keys_file);
- bool r = store_keys(m_keys_file, password, false);
+ bool r = store_keys(m_keys_file, password, m_watch_only);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
}
/*!
@@ -2854,74 +2858,7 @@ std::vector<std::vector<cryptonote::tx_destination_entry>> split_amounts(
return retVal;
}
} // anonymous namespace
-
-/**
- * @brief gets a monero address from the TXT record of a DNS entry
- *
- * gets the monero address from the TXT record of the DNS entry associated
- * with <url>. If this lookup fails, or the TXT record does not contain an
- * XMR address in the correct format, returns an empty string. <dnssec_valid>
- * will be set true or false according to whether or not the DNS query passes
- * DNSSEC validation.
- *
- * @param url the url to look up
- * @param dnssec_valid return-by-reference for DNSSEC status of query
- *
- * @return a monero address (as a string) or an empty string
- */
-std::vector<std::string> wallet2::addresses_from_url(const std::string& url, bool& dnssec_valid)
-{
- std::vector<std::string> addresses;
- // get txt records
- bool dnssec_available, dnssec_isvalid;
- std::string oa_addr = tools::DNSResolver::instance().get_dns_format_from_oa_address(url);
- auto records = tools::DNSResolver::instance().get_txt_record(oa_addr, dnssec_available, dnssec_isvalid);
-
- // TODO: update this to allow for conveying that dnssec was not available
- if (dnssec_available && dnssec_isvalid)
- {
- dnssec_valid = true;
- }
- else dnssec_valid = false;
-
- // for each txt record, try to find a monero address in it.
- for (auto& rec : records)
- {
- std::string addr = address_from_txt_record(rec);
- if (addr.size())
- {
- addresses.push_back(addr);
- }
- }
-
- return addresses;
-}
-
//----------------------------------------------------------------------------------------------------
-// TODO: parse the string in a less stupid way, probably with regex
-std::string wallet2::address_from_txt_record(const std::string& s)
-{
- // make sure the txt record has "oa1:xmr" and find it
- auto pos = s.find("oa1:xmr");
-
- // search from there to find "recipient_address="
- pos = s.find("recipient_address=", pos);
-
- pos += 18; // move past "recipient_address="
-
- // find the next semicolon
- auto pos2 = s.find(";", pos);
- if (pos2 != std::string::npos)
- {
- // length of address == 95, we can at least validate that much here
- if (pos2 - pos == 95)
- {
- return s.substr(pos, 95);
- }
- }
- return std::string();
-}
-
crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
{
std::vector<tx_extra_field> tx_extra_fields;
@@ -3018,14 +2955,19 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
for (auto &tx: ptx_vector)
txs.txes.push_back(tx.construction_data);
txs.transfers = m_transfers;
- std::string s = obj_to_json_str(txs);
- if (s.empty())
- return false;
- LOG_PRINT_L2("Saving unsigned tx data: " << s);
- // save as binary as there's no implementation of loading a json_archive
- if (!::serialization::dump_binary(txs, s))
+ // save as binary
+ std::ostringstream oss;
+ boost::archive::portable_binary_oarchive ar(oss);
+ try
+ {
+ ar << txs;
+ }
+ catch (...)
+ {
return false;
- return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + s);
+ }
+ LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
+ return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + oss.str());
}
//----------------------------------------------------------------------------------------------------
bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, std::function<bool(const unsigned_tx_set&)> accept_func)
@@ -3050,7 +2992,14 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s
return false;
}
unsigned_tx_set exported_txs;
- if (!::serialization::parse_binary(std::string(s.c_str() + magiclen, s.size() - magiclen), exported_txs))
+ s = s.substr(magiclen);
+ try
+ {
+ std::istringstream iss(s);
+ boost::archive::portable_binary_iarchive ar(iss);
+ ar >> exported_txs;
+ }
+ catch (...)
{
LOG_PRINT_L0("Failed to parse data from " << unsigned_filename);
return false;
@@ -3123,14 +3072,19 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s
signed_txes.key_images[i] = m_transfers[i].m_key_image;
}
- s = obj_to_json_str(signed_txes);
- if (s.empty())
- return false;
- LOG_PRINT_L2("Saving signed tx data: " << s);
- // save as binary as there's no implementation of loading a json_archive
- if (!::serialization::dump_binary(signed_txes, s))
+ // save as binary
+ std::ostringstream oss;
+ boost::archive::portable_binary_oarchive ar(oss);
+ try
+ {
+ ar << signed_txes;
+ }
+ catch(...)
+ {
return false;
- return epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + s);
+ }
+ LOG_PRINT_L2("Saving signed tx data: " << oss.str());
+ return epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + oss.str());
}
//----------------------------------------------------------------------------------------------------
bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func)
@@ -3156,7 +3110,14 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
LOG_PRINT_L0("Bad magic from " << signed_filename);
return false;
}
- if (!::serialization::parse_binary(std::string(s.c_str() + magiclen, s.size() - magiclen), signed_txs))
+ s = s.substr(magiclen);
+ try
+ {
+ std::istringstream iss(s);
+ boost::archive::portable_binary_iarchive ar(iss);
+ ar >> signed_txs;
+ }
+ catch (...)
{
LOG_PRINT_L0("Failed to parse data from " << signed_filename);
return false;
@@ -3521,6 +3482,23 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
outs.back().reserve(fake_outputs_count + 1);
const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
+ // make sure the real outputs we asked for are really included, along
+ // with the correct key and mask: this guards against an active attack
+ // where the node sends dummy data for all outputs, and we then send
+ // the real one, which the node can then tell from the fake outputs,
+ // as it has different data than the dummy data it had sent earlier
+ bool real_out_found = false;
+ for (size_t n = 0; n < requested_outputs_count; ++n)
+ {
+ size_t i = base + n;
+ if (req.outputs[i].index == td.m_global_output_index)
+ if (daemon_resp.outs[i].key == boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key)
+ if (daemon_resp.outs[i].mask == mask)
+ real_out_found = true;
+ }
+ THROW_WALLET_EXCEPTION_IF(!real_out_found, error::wallet_internal_error,
+ "Daemon response did not include the requested real output");
+
// pick real out first (it will be sorted when done)
outs.back().push_back(std::make_tuple(td.m_global_output_index, boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key, mask));
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 54e26008b..e1eafbae3 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -58,6 +58,8 @@
#include <iostream>
#define WALLET_RCP_CONNECTION_TIMEOUT 200000
+class Serialization_portability_wallet_Test;
+
namespace tools
{
class i_wallet2_callback
@@ -86,6 +88,7 @@ namespace tools
class wallet2
{
+ friend class ::Serialization_portability_wallet_Test;
public:
enum RefreshType {
RefreshFull,
@@ -201,17 +204,6 @@ namespace tools
uint64_t unlock_time;
bool use_rct;
std::vector<cryptonote::tx_destination_entry> dests; // original setup, does not include change
-
- BEGIN_SERIALIZE_OBJECT()
- FIELD(sources)
- FIELD(change_dts)
- FIELD(splitted_dsts)
- FIELD(selected_transfers)
- FIELD(extra)
- VARINT_FIELD(unlock_time)
- FIELD(use_rct)
- FIELD(dests)
- END_SERIALIZE()
};
typedef std::vector<transfer_details> transfer_container;
@@ -232,39 +224,18 @@ namespace tools
std::vector<cryptonote::tx_destination_entry> dests;
tx_construction_data construction_data;
-
- BEGIN_SERIALIZE_OBJECT()
- FIELD(tx)
- VARINT_FIELD(dust)
- VARINT_FIELD(fee)
- FIELD(dust_added_to_fee)
- FIELD(change_dts)
- FIELD(selected_transfers)
- FIELD(key_images)
- FIELD(tx_key)
- FIELD(dests)
- FIELD(construction_data)
- END_SERIALIZE()
};
struct unsigned_tx_set
{
std::vector<tx_construction_data> txes;
wallet2::transfer_container transfers;
- BEGIN_SERIALIZE_OBJECT()
- FIELD(txes)
- FIELD(transfers)
- END_SERIALIZE()
};
struct signed_tx_set
{
std::vector<pending_tx> ptx;
std::vector<crypto::key_image> key_images;
- BEGIN_SERIALIZE_OBJECT()
- FIELD(ptx)
- FIELD(key_images)
- END_SERIALIZE()
};
struct keys_file_data
@@ -503,10 +474,6 @@ namespace tools
static bool parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id);
static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id);
- static std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec_valid);
-
- static std::string address_from_txt_record(const std::string& s);
-
bool always_confirm_transfers() const { return m_always_confirm_transfers; }
void always_confirm_transfers(bool always) { m_always_confirm_transfers = always; }
bool store_tx_info() const { return m_store_tx_info; }
@@ -672,6 +639,10 @@ BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 16)
+BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
+BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
+BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 0)
+BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 0)
namespace boost
{
@@ -869,6 +840,48 @@ namespace boost
a & x.m_payment_id;
a & x.m_description;
}
+
+ template <class Archive>
+ inline void serialize(Archive &a, tools::wallet2::unsigned_tx_set &x, const boost::serialization::version_type ver)
+ {
+ a & x.txes;
+ a & x.transfers;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, tools::wallet2::signed_tx_set &x, const boost::serialization::version_type ver)
+ {
+ a & x.ptx;
+ a & x.key_images;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, tools::wallet2::tx_construction_data &x, const boost::serialization::version_type ver)
+ {
+ a & x.sources;
+ a & x.change_dts;
+ a & x.splitted_dsts;
+ a & x.selected_transfers;
+ a & x.extra;
+ a & x.unlock_time;
+ a & x.use_rct;
+ a & x.dests;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, tools::wallet2::pending_tx &x, const boost::serialization::version_type ver)
+ {
+ a & x.tx;
+ a & x.dust;
+ a & x.fee;
+ a & x.dust_added_to_fee;
+ a & x.change_dts;
+ a & x.selected_transfers;
+ a & x.key_images;
+ a & x.tx_key;
+ a & x.dests;
+ a & x.construction_data;
+ }
}
}
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 10590d357..e5707ad09 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -563,6 +563,12 @@ struct WalletManager
//! returns current mining hash rate (0 if not mining)
virtual double miningHashRate() const = 0;
+ //! returns current hard fork info
+ virtual void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const = 0;
+
+ //! returns current block target
+ virtual uint64_t blockTarget() const = 0;
+
//! resolves an OpenAlias address to a monero address
virtual std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const = 0;
};