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.h2
-rw-r--r--src/wallet/api/wallet2_api.h4
-rw-r--r--src/wallet/api/wallet_manager.cpp5
-rw-r--r--src/wallet/api/wallet_manager.h3
-rw-r--r--src/wallet/message_store.cpp2
-rw-r--r--src/wallet/message_store.h4
-rw-r--r--src/wallet/message_transporter.cpp8
-rw-r--r--src/wallet/message_transporter.h6
-rw-r--r--src/wallet/node_rpc_proxy.cpp2
-rw-r--r--src/wallet/node_rpc_proxy.h6
-rw-r--r--src/wallet/ringdb.cpp9
-rw-r--r--src/wallet/wallet2.cpp365
-rw-r--r--src/wallet/wallet2.h41
-rw-r--r--src/wallet/wallet_rpc_payments.cpp2
15 files changed, 285 insertions, 180 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 33047f703..4612b0397 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -725,7 +725,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &seed)
return recover(path, "", seed);
}
-bool WalletImpl::recover(const std::string &path, const std::string &password, const std::string &seed)
+bool WalletImpl::recover(const std::string &path, const std::string &password, const std::string &seed, const std::string &seed_offset/* = {}*/)
{
clearStatus();
m_errorString.clear();
@@ -743,6 +743,10 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c
setStatusError(tr("Electrum-style word list failed verification"));
return false;
}
+ if (!seed_offset.empty())
+ {
+ recovery_key = cryptonote::decrypt_key(recovery_key, seed_offset);
+ }
if (old_language == crypto::ElectrumWords::old_language_name)
old_language = Language::English().get_language_name();
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index e46a62340..66eeb0e73 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -60,7 +60,7 @@ public:
const std::string &language) const override;
bool open(const std::string &path, const std::string &password);
bool recover(const std::string &path,const std::string &password,
- const std::string &seed);
+ const std::string &seed, const std::string &seed_offset = {});
bool recoverFromKeysWithPassword(const std::string &path,
const std::string &password,
const std::string &language,
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index c0bae5cfd..6309724a4 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -1093,10 +1093,12 @@ struct WalletManager
* \param nettype Network type
* \param restoreHeight restore from start height
* \param kdf_rounds Number of rounds for key derivation function
+ * \param seed_offset Seed offset passphrase (optional)
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
*/
virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic,
- NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1) = 0;
+ NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1,
+ const std::string &seed_offset = {}) = 0;
Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic,
bool testnet = false, uint64_t restoreHeight = 0) // deprecated
{
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 8a40cdaaf..8d7541cea 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -93,13 +93,14 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path,
const std::string &mnemonic,
NetworkType nettype,
uint64_t restoreHeight,
- uint64_t kdf_rounds)
+ uint64_t kdf_rounds,
+ const std::string &seed_offset/* = {}*/)
{
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight);
}
- wallet->recover(path, password, mnemonic);
+ wallet->recover(path, password, mnemonic, seed_offset);
return wallet;
}
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 537fc5ba6..0595b8327 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -46,7 +46,8 @@ public:
const std::string &mnemonic,
NetworkType nettype,
uint64_t restoreHeight,
- uint64_t kdf_rounds = 1) override;
+ uint64_t kdf_rounds = 1,
+ const std::string &seed_offset = {}) override;
virtual Wallet * createWalletFromKeys(const std::string &path,
const std::string &password,
const std::string &language,
diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp
index 6e2cb933f..1bd462ef5 100644
--- a/src/wallet/message_store.cpp
+++ b/src/wallet/message_store.cpp
@@ -48,7 +48,7 @@
namespace mms
{
-message_store::message_store()
+message_store::message_store(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client) : m_transporter(std::move(http_client))
{
m_active = false;
m_auto_send = false;
diff --git a/src/wallet/message_store.h b/src/wallet/message_store.h
index 637bd29a1..d40daf186 100644
--- a/src/wallet/message_store.h
+++ b/src/wallet/message_store.h
@@ -43,6 +43,7 @@
#include "common/i18n.h"
#include "common/command_line.h"
#include "wipeable_string.h"
+#include "net/abstract_http_client.h"
#include "message_transporter.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -202,7 +203,8 @@ namespace mms
class message_store
{
public:
- message_store();
+ message_store(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client);
+
// Initialize and start to use the MMS, set the first signer, this wallet itself
// Filename, if not null and not empty, is used to create the ".mms" file
// reset it if already used, with deletion of all signers and messages
diff --git a/src/wallet/message_transporter.cpp b/src/wallet/message_transporter.cpp
index cf9b45b37..4dd4b8f01 100644
--- a/src/wallet/message_transporter.cpp
+++ b/src/wallet/message_transporter.cpp
@@ -80,7 +80,7 @@ namespace bitmessage_rpc
}
-message_transporter::message_transporter()
+message_transporter::message_transporter(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client) : m_http_client(std::move(http_client))
{
m_run = true;
}
@@ -96,7 +96,7 @@ void message_transporter::set_options(const std::string &bitmessage_address, con
}
m_bitmessage_login = bitmessage_login;
- m_http_client.set_server(address_parts.host, std::to_string(address_parts.port), boost::none);
+ m_http_client->set_server(address_parts.host, std::to_string(address_parts.port), boost::none);
}
bool message_transporter::receive_messages(const std::vector<std::string> &destination_transport_addresses,
@@ -256,7 +256,7 @@ bool message_transporter::post_request(const std::string &request, std::string &
additional_params.push_back(std::make_pair("Content-Type", "application/xml; charset=utf-8"));
const epee::net_utils::http::http_response_info* response = NULL;
std::chrono::milliseconds timeout = std::chrono::seconds(15);
- bool r = m_http_client.invoke("/", "POST", request, timeout, std::addressof(response), std::move(additional_params));
+ bool r = m_http_client->invoke("/", "POST", request, timeout, std::addressof(response), std::move(additional_params));
if (r)
{
answer = response->m_body;
@@ -266,7 +266,7 @@ bool message_transporter::post_request(const std::string &request, std::string &
LOG_ERROR("POST request to Bitmessage failed: " << request.substr(0, 300));
THROW_WALLET_EXCEPTION(tools::error::no_connection_to_bitmessage, m_bitmessage_url);
}
- m_http_client.disconnect(); // see comment above
+ m_http_client->disconnect(); // see comment above
std::string string_value = get_str_between_tags(answer, "<string>", "</string>");
if ((string_value.find("API Error") == 0) || (string_value.find("RPC ") == 0))
{
diff --git a/src/wallet/message_transporter.h b/src/wallet/message_transporter.h
index 28c099d87..84a2e9bae 100644
--- a/src/wallet/message_transporter.h
+++ b/src/wallet/message_transporter.h
@@ -34,9 +34,9 @@
#include "cryptonote_basic/cryptonote_basic.h"
#include "net/http_server_impl_base.h"
#include "net/http_client.h"
+#include "net/abstract_http_client.h"
#include "common/util.h"
#include "wipeable_string.h"
-#include "serialization/keyvalue_serialization.h"
#include <vector>
namespace mms
@@ -83,7 +83,7 @@ typedef epee::misc_utils::struct_init<transport_message_t> transport_message;
class message_transporter
{
public:
- message_transporter();
+ message_transporter(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client);
void set_options(const std::string &bitmessage_address, const epee::wipeable_string &bitmessage_login);
bool send_message(const transport_message &message);
bool receive_messages(const std::vector<std::string> &destination_transport_addresses,
@@ -94,7 +94,7 @@ public:
bool delete_transport_address(const std::string &transport_address);
private:
- epee::net_utils::http::http_simple_client m_http_client;
+ const std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client;
std::string m_bitmessage_url;
epee::wipeable_string m_bitmessage_login;
std::atomic<bool> m_run;
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index f3698b599..873c2ee51 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -51,7 +51,7 @@ namespace tools
static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
-NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex)
+NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::abstract_http_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex)
: m_http_client(http_client)
, m_rpc_payment_state(rpc_payment_state)
, m_daemon_rpc_mutex(mutex)
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 65ca40640..b053659e9 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -31,7 +31,7 @@
#include <string>
#include <boost/thread/mutex.hpp>
#include "include_base_utils.h"
-#include "net/http_client.h"
+#include "net/abstract_http_client.h"
#include "rpc/core_rpc_server_commands_defs.h"
#include "wallet_rpc_helpers.h"
@@ -41,7 +41,7 @@ namespace tools
class NodeRPCProxy
{
public:
- NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex);
+ NodeRPCProxy(epee::net_utils::http::abstract_http_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex);
void set_client_secret_key(const crypto::secret_key &skey) { m_client_id_secret_key = skey; }
void invalidate();
@@ -72,7 +72,7 @@ private:
private:
boost::optional<std::string> get_info();
- epee::net_utils::http::http_simple_client &m_http_client;
+ epee::net_utils::http::abstract_http_client &m_http_client;
rpc_payment_state_t &m_rpc_payment_state;
boost::recursive_mutex &m_daemon_rpc_mutex;
crypto::secret_key m_client_id_secret_key;
diff --git a/src/wallet/ringdb.cpp b/src/wallet/ringdb.cpp
index 5e88ea788..dfeb987ca 100644
--- a/src/wallet/ringdb.cpp
+++ b/src/wallet/ringdb.cpp
@@ -35,6 +35,7 @@
#include "misc_language.h"
#include "wallet_errors.h"
#include "ringdb.h"
+#include "cryptonote_config.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.ringdb"
@@ -105,13 +106,11 @@ std::string get_rings_filename(boost::filesystem::path filename)
static crypto::chacha_iv make_iv(const crypto::key_image &key_image, const crypto::chacha_key &key, uint8_t field)
{
- static const char salt[] = "ringdsb";
-
- uint8_t buffer[sizeof(key_image) + sizeof(key) + sizeof(salt) + sizeof(field)];
+ uint8_t buffer[sizeof(key_image) + sizeof(key) + sizeof(config::HASH_KEY_RINGDB) + sizeof(field)];
memcpy(buffer, &key_image, sizeof(key_image));
memcpy(buffer + sizeof(key_image), &key, sizeof(key));
- memcpy(buffer + sizeof(key_image) + sizeof(key), salt, sizeof(salt));
- memcpy(buffer + sizeof(key_image) + sizeof(key) + sizeof(salt), &field, sizeof(field));
+ memcpy(buffer + sizeof(key_image) + sizeof(key), config::HASH_KEY_RINGDB, sizeof(config::HASH_KEY_RINGDB));
+ memcpy(buffer + sizeof(key_image) + sizeof(key) + sizeof(config::HASH_KEY_RINGDB), &field, sizeof(field));
crypto::hash hash;
// if field is 0, backward compat mode: hash without the field
crypto::cn_fast_hash(buffer, sizeof(buffer) - !field, hash.data);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 6d2fff17b..4220f18be 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -102,10 +102,6 @@ using namespace cryptonote;
// used to target a given block weight (additional outputs may be added on top to build fee)
#define TX_WEIGHT_TARGET(bytes) (bytes*2/3)
-// arbitrary, used to generate different hashes from the same input
-#define CHACHA8_KEY_TAIL 0x8c
-#define CACHE_KEY_TAIL 0x8d
-
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\004"
#define SIGNED_TX_PREFIX "Monero signed tx set\004"
#define MULTISIG_UNSIGNED_TX_PREFIX "Monero multisig unsigned tx set\001"
@@ -240,8 +236,6 @@ namespace
add_reason(reason, "overspend");
if (res.fee_too_low)
add_reason(reason, "fee too low");
- if (res.not_rct)
- add_reason(reason, "tx is not ringct");
if (res.sanity_check_failed)
add_reason(reason, "tx sanity check failed");
if (res.not_relayed)
@@ -361,7 +355,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
else if (!daemon_ssl_ca_file.empty() || !daemon_ssl_allowed_fingerprints.empty())
{
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() };
- std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
+ std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex_locale::to_vector);
for (const auto &fpr: ssl_allowed_fingerprints)
{
THROW_WALLET_EXCEPTION_IF(fpr.size() != SSL_FINGERPRINT_SIZE, tools::error::wallet_internal_error,
@@ -441,6 +435,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
verification_required && !ssl_options.has_strong_verification(real_daemon),
tools::error::wallet_internal_error,
tools::wallet2::tr("Enabling --") + std::string{use_proxy ? opts.proxy.name : opts.daemon_ssl.name} + tools::wallet2::tr(" requires --") +
+ opts.daemon_ssl_allow_any_cert.name + tools::wallet2::tr(" or --") +
opts.daemon_ssl_ca_certificates.name + tools::wallet2::tr(" or --") + opts.daemon_ssl_allowed_fingerprints.name + tools::wallet2::tr(" or use of a .onion/.i2p domain")
);
}
@@ -1127,7 +1122,8 @@ void wallet_device_callback::on_progress(const hw::device_progress& event)
wallet->on_device_progress(event);
}
-wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
+wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory):
+ m_http_client(std::move(http_client_factory->create())),
m_multisig_rescan_info(NULL),
m_multisig_rescan_k(NULL),
m_upper_transaction_weight_limit(0),
@@ -1172,7 +1168,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_watch_only(false),
m_multisig(false),
m_multisig_threshold(0),
- m_node_rpc_proxy(m_http_client, m_rpc_payment_state, m_daemon_rpc_mutex),
+ m_node_rpc_proxy(*m_http_client, m_rpc_payment_state, m_daemon_rpc_mutex),
m_account_public_address{crypto::null_pkey, crypto::null_pkey},
m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR),
m_subaddress_lookahead_minor(SUBADDRESS_LOOKAHEAD_MINOR),
@@ -1183,7 +1179,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_light_wallet_balance(0),
m_light_wallet_unlocked_balance(0),
m_original_keys_available(false),
- m_message_store(),
+ m_message_store(http_client_factory->create()),
m_key_device_type(hw::device::device_type::SOFTWARE),
m_ring_history_saved(false),
m_ringdb(),
@@ -1303,8 +1299,8 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
{
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
- if(m_http_client.is_connected())
- m_http_client.disconnect();
+ if(m_http_client->is_connected())
+ m_http_client->disconnect();
const bool changed = m_daemon_address != daemon_address;
m_daemon_address = std::move(daemon_address);
m_daemon_login = std::move(daemon_login);
@@ -1318,7 +1314,7 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
const std::string address = get_daemon_address();
MINFO("setting daemon to " << address);
- bool ret = m_http_client.set_server(address, get_daemon_login(), std::move(ssl_options));
+ bool ret = m_http_client->set_server(address, get_daemon_login(), std::move(ssl_options));
if (ret)
{
CRITICAL_REGION_LOCAL(default_daemon_address_lock);
@@ -1333,7 +1329,12 @@ bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::
m_is_initialized = true;
m_upper_transaction_weight_limit = upper_transaction_weight_limit;
if (proxy != boost::asio::ip::tcp::endpoint{})
- m_http_client.set_connector(net::socks::connector{std::move(proxy)});
+ {
+ epee::net_utils::http::abstract_http_client* abstract_http_client = m_http_client.get();
+ epee::net_utils::http::http_simple_client* http_simple_client = dynamic_cast<epee::net_utils::http::http_simple_client*>(abstract_http_client);
+ CHECK_AND_ASSERT_MES(http_simple_client != nullptr, false, "http_simple_client must be used to set proxy");
+ http_simple_client->set_connector(net::socks::connector{std::move(proxy)});
+ }
return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options));
}
//----------------------------------------------------------------------------------------------------
@@ -1558,6 +1559,12 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
}
}
//----------------------------------------------------------------------------------------------------
+void wallet2::create_one_off_subaddress(const cryptonote::subaddress_index& index)
+{
+ const crypto::public_key pkey = get_subaddress_spend_public_key(index);
+ m_subaddresses[pkey] = index;
+}
+//----------------------------------------------------------------------------------------------------
std::string wallet2::get_subaddress_label(const cryptonote::subaddress_index& index) const
{
if (index.major >= m_subaddress_labels.size() || index.minor >= m_subaddress_labels[index.major].size())
@@ -2099,7 +2106,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
- expand_subaddresses(tx_scan_info[o].received->index);
+ if (tx_scan_info[o].received->index.major < m_subaddress_labels.size() && tx_scan_info[o].received->index.minor < m_subaddress_labels[tx_scan_info[o].received->index.major].size())
+ expand_subaddresses(tx_scan_info[o].received->index);
if (tx.vout[o].amount == 0)
{
td.m_mask = tx_scan_info[o].mask;
@@ -2177,7 +2185,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
- expand_subaddresses(tx_scan_info[o].received->index);
+ if (tx_scan_info[o].received->index.major < m_subaddress_labels.size() && tx_scan_info[o].received->index.minor < m_subaddress_labels[tx_scan_info[o].received->index.major].size())
+ expand_subaddresses(tx_scan_info[o].received->index);
if (tx.vout[o].amount == 0)
{
td.m_mask = tx_scan_info[o].mask;
@@ -2590,7 +2599,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "getblocks.bin", error::get_blocks_error, get_rpc_status(res.status));
THROW_WALLET_EXCEPTION_IF(res.blocks.size() != res.output_indices.size(), error::wallet_internal_error,
"mismatched blocks (" + boost::lexical_cast<std::string>(res.blocks.size()) + ") and output_indices (" +
@@ -2619,7 +2628,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
req.client = get_client_signature();
uint64_t pre_call_credits = m_rpc_payment_state.credits;
- bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "gethashes.bin", error::get_hashes_error, get_rpc_status(res.status));
check_rpc_cost("/gethashes.bin", res.credits, pre_call_credits, 1 + res.m_block_ids.size() * COST_PER_BLOCK_HASH);
}
@@ -2904,7 +2913,7 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_transaction_pool_hashes.bin", error::get_tx_pool_error);
check_rpc_cost("/get_transaction_pool_hashes.bin", res.credits, pre_call_credits, 1 + res.tx_hashes.size() * COST_PER_POOL_HASH);
}
@@ -3049,7 +3058,7 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
if (r && res.status == CORE_RPC_STATUS_OK)
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, res.txs.size() * COST_PER_TX);
}
@@ -3535,7 +3544,7 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, m_http_client, rpc_timeout);
+ r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/get_output_distribution.bin");
check_rpc_cost("/get_output_distribution.bin", res.credits, pre_call_credits, COST_PER_OUTPUT_DISTRIBUTION_0);
}
@@ -3694,6 +3703,30 @@ void wallet2::clear_soft(bool keep_key_images)
*/
bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable_string& password, bool watch_only)
{
+ boost::optional<wallet2::keys_file_data> keys_file_data = get_keys_file_data(password, watch_only);
+ CHECK_AND_ASSERT_MES(keys_file_data != boost::none, false, "failed to generate wallet keys data");
+
+ std::string tmp_file_name = keys_file_name + ".new";
+ std::string buf;
+ bool r = ::serialization::dump_binary(keys_file_data.get(), buf);
+ r = r && save_to_file(tmp_file_name, buf);
+ CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
+
+ unlock_keys_file();
+ std::error_code e = tools::replace_file(tmp_file_name, keys_file_name);
+ lock_keys_file();
+
+ if (e) {
+ boost::filesystem::remove(tmp_file_name);
+ LOG_ERROR("failed to update wallet keys file " << keys_file_name);
+ return false;
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::wipeable_string& password, bool watch_only)
+{
std::string account_data;
std::string multisig_signers;
std::string multisig_derivations;
@@ -3714,8 +3747,8 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
account.encrypt_keys(key);
bool r = epee::serialization::store_t_to_binary(account, account_data);
- CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet keys");
- wallet2::keys_file_data keys_file_data = {};
+ CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet keys");
+ boost::optional<wallet2::keys_file_data> keys_file_data = (wallet2::keys_file_data) {};
// Create a JSON object with "key_data" and "seed_language" as keys.
rapidjson::Document json;
@@ -3746,12 +3779,12 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
if (m_multisig)
{
bool r = ::serialization::dump_binary(m_multisig_signers, multisig_signers);
- CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet multisig signers");
+ CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet multisig signers");
value.SetString(multisig_signers.c_str(), multisig_signers.length());
json.AddMember("multisig_signers", value, json.GetAllocator());
r = ::serialization::dump_binary(m_multisig_derivations, multisig_derivations);
- CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet multisig derivations");
+ CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet multisig derivations");
value.SetString(multisig_derivations.c_str(), multisig_derivations.length());
json.AddMember("multisig_derivations", value, json.GetAllocator());
@@ -3894,27 +3927,10 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
// Encrypt the entire JSON object.
std::string cipher;
cipher.resize(account_data.size());
- keys_file_data.iv = crypto::rand<crypto::chacha_iv>();
- crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]);
- keys_file_data.account_data = cipher;
-
- std::string tmp_file_name = keys_file_name + ".new";
- std::string buf;
- r = ::serialization::dump_binary(keys_file_data, buf);
- r = r && save_to_file(tmp_file_name, buf);
- CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
-
- unlock_keys_file();
- std::error_code e = tools::replace_file(tmp_file_name, keys_file_name);
- lock_keys_file();
-
- if (e) {
- boost::filesystem::remove(tmp_file_name);
- LOG_ERROR("failed to update wallet keys file " << keys_file_name);
- return false;
- }
-
- return true;
+ keys_file_data.get().iv = crypto::rand<crypto::chacha_iv>();
+ crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.get().iv, &cipher[0]);
+ keys_file_data.get().account_data = cipher;
+ return keys_file_data;
}
//----------------------------------------------------------------------------------------------------
void wallet2::setup_keys(const epee::wipeable_string &password)
@@ -3932,7 +3948,7 @@ void wallet2::setup_keys(const epee::wipeable_string &password)
static_assert(HASH_SIZE == sizeof(crypto::chacha_key), "Mismatched sizes of hash and chacha key");
epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE+1>> cache_key_data;
memcpy(cache_key_data.data(), &key, HASH_SIZE);
- cache_key_data[HASH_SIZE] = CACHE_KEY_TAIL;
+ cache_key_data[HASH_SIZE] = config::HASH_KEY_WALLET_CACHE;
cn_fast_hash(cache_key_data.data(), HASH_SIZE+1, (crypto::hash&)m_cache_key);
get_ringdb_key();
}
@@ -3954,16 +3970,51 @@ void wallet2::change_password(const std::string &filename, const epee::wipeable_
*/
bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_string& password)
{
- rapidjson::Document json;
- wallet2::keys_file_data keys_file_data;
- std::string buf;
- bool encrypted_secret_keys = false;
- bool r = load_from_file(keys_file_name, buf);
+ std::string keys_file_buf;
+ bool r = load_from_file(keys_file_name, keys_file_buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
+ // Load keys from buffer
+ boost::optional<crypto::chacha_key> keys_to_encrypt;
+ try {
+ r = wallet2::load_keys_buf(keys_file_buf, password, keys_to_encrypt);
+ } catch (const std::exception& e) {
+ std::size_t found = string(e.what()).find("failed to deserialize keys buffer");
+ THROW_WALLET_EXCEPTION_IF(found != std::string::npos, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
+ throw e;
+ }
+
+ // Rewrite with encrypted keys if unencrypted, ignore errors
+ if (r && keys_to_encrypt != boost::none)
+ {
+ if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
+ encrypt_keys(keys_to_encrypt.get());
+ bool saved_ret = store_keys(keys_file_name, password, m_watch_only);
+ if (!saved_ret)
+ {
+ // just moan a bit, but not fatal
+ MERROR("Error saving keys file with encrypted keys, not fatal");
+ }
+ if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
+ decrypt_keys(keys_to_encrypt.get());
+ m_keys_file_locker.reset();
+ }
+ return r;
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password) {
+ boost::optional<crypto::chacha_key> keys_to_encrypt;
+ return wallet2::load_keys_buf(keys_buf, password, keys_to_encrypt);
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password, boost::optional<crypto::chacha_key>& keys_to_encrypt) {
+
// Decrypt the contents
- r = ::serialization::parse_binary(buf, keys_file_data);
- THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
+ rapidjson::Document json;
+ wallet2::keys_file_data keys_file_data;
+ bool encrypted_secret_keys = false;
+ bool r = ::serialization::parse_binary(keys_buf, keys_file_data);
+ THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize keys buffer");
crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
std::string account_data;
@@ -4247,8 +4298,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
}
else
{
- THROW_WALLET_EXCEPTION(error::wallet_internal_error, "invalid password");
- return false;
+ THROW_WALLET_EXCEPTION(error::wallet_internal_error, "invalid password");
+ return false;
}
r = epee::serialization::load_t_from_binary(m_account, account_data);
@@ -4282,24 +4333,13 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
}
else
{
- // rewrite with encrypted keys, ignore errors
- if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
- encrypt_keys(key);
- bool saved_ret = store_keys(keys_file_name, password, m_watch_only);
- if (!saved_ret)
- {
- // just moan a bit, but not fatal
- MERROR("Error saving keys file with encrypted keys, not fatal");
- }
- if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
- decrypt_keys(key);
- m_keys_file_locker.reset();
+ keys_to_encrypt = key;
}
}
const cryptonote::account_keys& keys = m_account.get_keys();
hw::device &hwdev = m_account.get_device();
r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
- if(!m_watch_only && !m_multisig && hwdev.device_protocol() != hw::device::PROTOCOL_COLD)
+ if (!m_watch_only && !m_multisig && hwdev.device_protocol() != hw::device::PROTOCOL_COLD)
r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file);
@@ -4918,7 +4958,8 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
// re-encrypt keys
keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
- create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
+ if (!m_wallet_file.empty())
+ create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
setup_new_blockchain();
@@ -5058,7 +5099,9 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
++m_multisig_rounds_passed;
- create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
+ if (!m_wallet_file.empty())
+ create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
+
return extra_multisig_info;
}
@@ -5432,13 +5475,13 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
{
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
- if(!m_http_client.is_connected(ssl))
+ if(!m_http_client->is_connected(ssl))
{
m_rpc_version = 0;
m_node_rpc_proxy.invalidate();
- if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
+ if (!m_http_client->connect(std::chrono::milliseconds(timeout)))
return false;
- if(!m_http_client.is_connected(ssl))
+ if(!m_http_client->is_connected(ssl))
return false;
}
}
@@ -5466,12 +5509,12 @@ void wallet2::set_offline(bool offline)
{
m_offline = offline;
m_node_rpc_proxy.set_offline(offline);
- m_http_client.set_auto_connect(!offline);
+ m_http_client->set_auto_connect(!offline);
if (offline)
{
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
- if(m_http_client.is_connected())
- m_http_client.disconnect();
+ if(m_http_client->is_connected())
+ m_http_client->disconnect();
}
}
//----------------------------------------------------------------------------------------------------
@@ -5486,48 +5529,63 @@ void wallet2::generate_chacha_key_from_password(const epee::wipeable_string &pas
crypto::generate_chacha_key(pass.data(), pass.size(), key, m_kdf_rounds);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password)
+void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password, const std::string& keys_buf, const std::string& cache_buf)
{
clear();
prepare_file_names(wallet_);
+ // determine if loading from file system or string buffer
+ bool use_fs = !wallet_.empty();
+ THROW_WALLET_EXCEPTION_IF((use_fs && !keys_buf.empty()) || (!use_fs && keys_buf.empty()), error::file_read_error, "must load keys either from file system or from buffer");\
+
boost::system::error_code e;
- bool exists = boost::filesystem::exists(m_keys_file, e);
- THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file);
- lock_keys_file();
- THROW_WALLET_EXCEPTION_IF(!is_keys_file_locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program");
+ if (use_fs)
+ {
+ bool exists = boost::filesystem::exists(m_keys_file, e);
+ THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file);
+ lock_keys_file();
+ THROW_WALLET_EXCEPTION_IF(!is_keys_file_locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program");
- // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
- unlock_keys_file();
- if (!load_keys(m_keys_file, password))
+ // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
+ unlock_keys_file();
+ if (!load_keys(m_keys_file, password))
+ {
+ THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, m_keys_file);
+ }
+ LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype));
+ lock_keys_file();
+ }
+ else if (!load_keys_buf(keys_buf, password))
{
- THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, m_keys_file);
+ THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, "failed to load keys from buffer");
}
- LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype));
- lock_keys_file();
wallet_keys_unlocker unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, password);
//keys loaded ok!
//try to load wallet file. but even if we failed, it is not big problem
- if(!boost::filesystem::exists(m_wallet_file, e) || e)
+ if (use_fs && (!boost::filesystem::exists(m_wallet_file, e) || e))
{
LOG_PRINT_L0("file not found: " << m_wallet_file << ", starting with empty blockchain");
m_account_public_address = m_account.get_keys().m_account_address;
}
- else
+ else if (use_fs || !cache_buf.empty())
{
wallet2::cache_file_data cache_file_data;
- std::string buf;
- bool r = load_from_file(m_wallet_file, buf, std::numeric_limits<size_t>::max());
- THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
+ std::string cache_file_buf;
+ bool r = true;
+ if (use_fs)
+ {
+ load_from_file(m_wallet_file, cache_file_buf, std::numeric_limits<size_t>::max());
+ THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
+ }
// try to read it as an encrypted cache
try
{
LOG_PRINT_L1("Trying to decrypt cache data");
- r = ::serialization::parse_binary(buf, cache_file_data);
+ r = ::serialization::parse_binary(use_fs ? cache_file_buf : cache_buf, cache_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"');
std::string cache_data;
cache_data.resize(cache_file_data.cache_data.size());
@@ -5564,7 +5622,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
catch (...)
{
LOG_PRINT_L0("Failed to open portable binary, trying unportable");
- boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
+ if (use_fs) boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
std::stringstream iss;
iss.str("");
iss << cache_data;
@@ -5579,17 +5637,17 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
LOG_PRINT_L1("Failed to load encrypted cache, trying unencrypted");
try {
std::stringstream iss;
- iss << buf;
+ iss << cache_file_buf;
boost::archive::portable_binary_iarchive ar(iss);
ar >> *this;
}
catch (...)
{
LOG_PRINT_L0("Failed to open portable binary, trying unportable");
- boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
+ if (use_fs) boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
std::stringstream iss;
iss.str("");
- iss << buf;
+ iss << cache_file_buf;
boost::archive::binary_iarchive ar(iss);
ar >> *this;
}
@@ -5633,7 +5691,8 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
try
{
- m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
+ if (use_fs)
+ m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
}
catch (const std::exception &e)
{
@@ -5661,7 +5720,7 @@ void wallet2::trim_hashchain()
req.height = m_blockchain.size() - 1;
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, m_http_client, rpc_timeout);
+ r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, *m_http_client, rpc_timeout);
if (r && res.status == CORE_RPC_STATUS_OK)
check_rpc_cost("getblockheaderbyheight", res.credits, pre_call_credits, COST_PER_BLOCK_HEADER);
}
@@ -5736,18 +5795,10 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
}
}
}
- // preparing wallet data
- std::stringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- ar << *this;
- wallet2::cache_file_data cache_file_data = {};
- cache_file_data.cache_data = oss.str();
- std::string cipher;
- cipher.resize(cache_file_data.cache_data.size());
- cache_file_data.iv = crypto::rand<crypto::chacha_iv>();
- crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cipher[0]);
- cache_file_data.cache_data = cipher;
+ // get wallet cache data
+ boost::optional<wallet2::cache_file_data> cache_file_data = get_cache_file_data(password);
+ THROW_WALLET_EXCEPTION_IF(cache_file_data == boost::none, error::wallet_internal_error, "failed to generate wallet cache data");
const std::string new_file = same_file ? m_wallet_file + ".new" : path;
const std::string old_file = m_wallet_file;
@@ -5798,7 +5849,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
// The price to pay is temporary higher memory consumption for string stream + binary archive
std::ostringstream oss;
binary_archive<true> oar(oss);
- bool success = ::serialization::serialize(oar, cache_file_data);
+ bool success = ::serialization::serialize(oar, cache_file_data.get());
if (success) {
success = save_to_file(new_file, oss.str());
}
@@ -5807,7 +5858,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
std::ofstream ostr;
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
binary_archive<true> oar(ostr);
- bool success = ::serialization::serialize(oar, cache_file_data);
+ bool success = ::serialization::serialize(oar, cache_file_data.get());
ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
#endif
@@ -5823,7 +5874,30 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
// store should only exist if the MMS is really active
m_message_store.write_to_file(get_multisig_wallet_state(), m_mms_file);
}
-
+}
+//----------------------------------------------------------------------------------------------------
+boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data(const epee::wipeable_string &passwords)
+{
+ trim_hashchain();
+ try
+ {
+ std::stringstream oss;
+ boost::archive::portable_binary_oarchive ar(oss);
+ ar << *this;
+
+ boost::optional<wallet2::cache_file_data> cache_file_data = (wallet2::cache_file_data) {};
+ cache_file_data.get().cache_data = oss.str();
+ std::string cipher;
+ cipher.resize(cache_file_data.get().cache_data.size());
+ cache_file_data.get().iv = crypto::rand<crypto::chacha_iv>();
+ crypto::chacha20(cache_file_data.get().cache_data.data(), cache_file_data.get().cache_data.size(), m_cache_key, cache_file_data.get().iv, &cipher[0]);
+ cache_file_data.get().cache_data = cipher;
+ return cache_file_data;
+ }
+ catch(...)
+ {
+ return boost::none;
+ }
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(uint32_t index_major, bool strict) const
@@ -6027,7 +6101,7 @@ void wallet2::rescan_spent()
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, daemon_resp, "is_key_image_spent", error::is_key_image_spent_error, get_rpc_status(daemon_resp.status));
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != n_outputs, error::wallet_internal_error,
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
@@ -6356,7 +6430,7 @@ void wallet2::commit_tx(pending_tx& ptx)
oreq.tx = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
{
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
- bool r = epee::net_utils::invoke_http_json("/submit_raw_tx", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = epee::net_utils::invoke_http_json("/submit_raw_tx", oreq, ores, *m_http_client, rpc_timeout, "POST");
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "submit_raw_tx");
// MyMonero and OpenMonero use different status strings
THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, get_rpc_status(ores.status), ores.error);
@@ -6375,7 +6449,7 @@ void wallet2::commit_tx(pending_tx& ptx)
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, daemon_send_resp, "sendrawtransaction", error::tx_rejected, ptx.tx, get_rpc_status(daemon_send_resp.status), get_text_reason(daemon_send_resp));
check_rpc_cost("/sendrawtransaction", daemon_send_resp.credits, pre_call_credits, COST_PER_TX_RELAY);
}
@@ -7347,7 +7421,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
getbh_req.client = get_client_signature();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, getbh_res, "getblockheadersrange", error::get_blocks_error, get_rpc_status(getbh_res.status));
check_rpc_cost("/sendrawtransaction", getbh_res.credits, pre_call_credits, N * COST_PER_BLOCK_HEADER);
}
@@ -7573,7 +7647,7 @@ bool wallet2::find_and_save_rings(bool force)
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/gettransactions");
THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error,
"daemon returned wrong response for gettransactions, wrong txs count = " +
@@ -7721,7 +7795,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
{
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
- bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, *m_http_client, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
@@ -7908,7 +7982,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req_t.client = get_client_signature();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_histogram", error::get_histogram_error, get_rpc_status(resp_t.status));
check_rpc_cost("get_output_histogram", resp_t.credits, pre_call_credits, COST_PER_OUTPUT_HISTOGRAM * req_t.amounts.size());
}
@@ -7934,7 +8008,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req_t.client = get_client_signature();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, *m_http_client, rpc_timeout * 1000);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_distribution", error::get_output_distribution, get_rpc_status(resp_t.status));
uint64_t expected_cost = 0;
for (uint64_t amount: req_t.amounts) expected_cost += (amount ? COST_PER_OUTPUT_DISTRIBUTION : COST_PER_OUTPUT_DISTRIBUTION_0);
@@ -8288,7 +8362,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, daemon_resp, "get_outs.bin", error::get_outs_error, get_rpc_status(daemon_resp.status));
THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != req.outputs.size(), error::wallet_internal_error,
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
@@ -10497,7 +10571,7 @@ uint8_t wallet2::get_current_hard_fork()
m_daemon_rpc_mutex.lock();
req_t.version = 0;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, *m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, tools::error::no_connection_to_daemon, "hard_fork_info");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, "hard_fork_info");
@@ -10592,7 +10666,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req_t.client = get_client_signature();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_histogram", error::get_histogram_error, resp_t.status);
uint64_t cost = req_t.amounts.empty() ? COST_PER_FULL_OUTPUT_HISTOGRAM : (COST_PER_OUTPUT_HISTOGRAM * req_t.amounts.size());
check_rpc_cost("get_output_histogram", resp_t.credits, pre_call_credits, cost);
@@ -10634,7 +10708,7 @@ uint64_t wallet2::get_num_rct_outputs()
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req_t.client = get_client_signature();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_histogram", error::get_histogram_error, resp_t.status);
THROW_WALLET_EXCEPTION_IF(resp_t.histogram.size() != 1, error::get_histogram_error, "Expected exactly one response");
THROW_WALLET_EXCEPTION_IF(resp_t.histogram[0].amount != 0, error::get_histogram_error, "Expected 0 amount");
@@ -10765,7 +10839,7 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
req.client = get_client_signature();
uint64_t pre_call_credits = m_rpc_payment_state.credits;
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, res.txs.size() * COST_PER_TX);
@@ -10818,7 +10892,7 @@ void wallet2::set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/gettransactions");
THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
"daemon returned wrong response for gettransactions, wrong txs count = " +
@@ -10871,7 +10945,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
"daemon returned wrong response for gettransactions, wrong txs count = " +
@@ -10935,7 +11009,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
+ r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_outs.bin", error::get_outs_error, res.status);
THROW_WALLET_EXCEPTION_IF(res.outs.size() != ring_size, error::wallet_internal_error,
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
@@ -10993,7 +11067,7 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
"daemon returned wrong response for gettransactions, wrong txs count = " +
@@ -11068,7 +11142,7 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
+ r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_outs.bin", error::get_outs_error, res.status);
THROW_WALLET_EXCEPTION_IF(res.outs.size() != req.outputs.size(), error::wallet_internal_error,
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
@@ -11170,7 +11244,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, COST_PER_TX);
@@ -11225,7 +11299,7 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ ok = net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, COST_PER_TX);
@@ -11386,7 +11460,7 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ ok = net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, COST_PER_TX);
@@ -11683,7 +11757,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
gettx_req.client = get_client_signature();
- bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, m_http_client);
+ bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, *m_http_client);
THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
error::wallet_internal_error, "Failed to get transaction from daemon");
check_rpc_cost("/gettransactions", gettx_res.credits, pre_call_credits, gettx_res.txs.size() * COST_PER_TX);
@@ -11700,7 +11774,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
kispent_req.client = get_client_signature();
- ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, m_http_client, rpc_timeout);
+ ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, *m_http_client, rpc_timeout);
THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
error::wallet_internal_error, "Failed to get key image spent status from daemon");
check_rpc_cost("/is_key_image_spent", kispent_res.credits, pre_call_credits, kispent_res.spent_status.size() * COST_PER_KEY_IMAGE);
@@ -12274,7 +12348,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, daemon_resp, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
@@ -12363,7 +12437,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
gettxs_req.client = get_client_signature();
uint64_t pre_call_credits = m_rpc_payment_state.credits;
- bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, gettxs_res, "gettransactions");
THROW_WALLET_EXCEPTION_IF(gettxs_res.txs.size() != spent_txids.size(), error::wallet_internal_error,
"daemon returned wrong response for gettransactions, wrong count = " + std::to_string(gettxs_res.txs.size()) + ", expected " + std::to_string(spent_txids.size()));
@@ -12681,7 +12755,8 @@ process:
const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
- expand_subaddresses(td.m_subaddr_index);
+ if (td.m_subaddr_index.major < m_subaddress_labels.size() && td.m_subaddr_index.minor < m_subaddress_labels[td.m_subaddr_index.major].size())
+ expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
td.m_key_image_request = true;
td.m_key_image_partial = false;
@@ -13303,7 +13378,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, m_http_client, rpc_timeout);
+ r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, *m_http_client, rpc_timeout);
if (r && res.status == CORE_RPC_STATUS_OK)
check_rpc_cost("/getblocks_by_height.bin", res.credits, pre_call_credits, 3 * COST_PER_BLOCK);
}
@@ -13381,7 +13456,7 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_txpool_backlog", error::get_tx_pool_error);
check_rpc_cost("get_txpool_backlog", res.credits, pre_call_credits, COST_PER_TX_POOL_STATS * res.backlog.size());
}
@@ -13720,12 +13795,12 @@ void wallet2::finish_rescan_bc_keep_key_images(uint64_t transfer_height, const c
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_bytes_sent() const
{
- return m_http_client.get_bytes_sent();
+ return m_http_client->get_bytes_sent();
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_bytes_received() const
{
- return m_http_client.get_bytes_received();
+ return m_http_client->get_bytes_received();
}
//----------------------------------------------------------------------------------------------------
std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
@@ -13738,7 +13813,7 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
{
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
- bool r = epee::net_utils::invoke_http_json("/get_public_nodes", req, res, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json("/get_public_nodes", req, res, *m_http_client, rpc_timeout);
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/get_public_nodes");
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 1dac8acac..1c3c00152 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -269,7 +269,7 @@ private:
static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds);
static bool query_device(hw::device::device_type& device_type, const std::string& keys_file_name, const epee::wipeable_string& password, uint64_t kdf_rounds = 1);
- wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false);
+ wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = std::unique_ptr<epee::net_utils::http::http_simple_client_factory>(new epee::net_utils::http::http_simple_client_factory()));
~wallet2();
struct multisig_info
@@ -708,7 +708,7 @@ private:
*/
void rewrite(const std::string& wallet_name, const epee::wipeable_string& password);
void write_watch_only_wallet(const std::string& wallet_name, const epee::wipeable_string& password, std::string &new_keys_filename);
- void load(const std::string& wallet, const epee::wipeable_string& password);
+ void load(const std::string& wallet, const epee::wipeable_string& password, const std::string& keys_buf = "", const std::string& cache_buf = "");
void store();
/*!
* \brief store_to Stores wallet to another file(s), deleting old ones
@@ -716,6 +716,19 @@ private:
* \param password Password to protect new wallet (TODO: probably better save the password in the wallet object?)
*/
void store_to(const std::string &path, const epee::wipeable_string &password);
+ /*!
+ * \brief get_keys_file_data Get wallet keys data which can be stored to a wallet file.
+ * \param password Password of the encrypted wallet buffer (TODO: probably better save the password in the wallet object?)
+ * \param watch_only true to include only view key, false to include both spend and view keys
+ * \return Encrypted wallet keys data which can be stored to a wallet file
+ */
+ boost::optional<wallet2::keys_file_data> get_keys_file_data(const epee::wipeable_string& password, bool watch_only);
+ /*!
+ * \brief get_cache_file_data Get wallet cache data which can be stored to a wallet file.
+ * \param password Password to protect the wallet cache data (TODO: probably better save the password in the wallet object?)
+ * \return Encrypted wallet cache data which can be stored to a wallet file
+ */
+ boost::optional<wallet2::cache_file_data> get_cache_file_data(const epee::wipeable_string& password);
std::string path() const;
@@ -793,6 +806,7 @@ private:
size_t get_num_subaddresses(uint32_t index_major) const { return index_major < m_subaddress_labels.size() ? m_subaddress_labels[index_major].size() : 0; }
void add_subaddress(uint32_t index_major, const std::string& label); // throws when index is out of bound
void expand_subaddresses(const cryptonote::subaddress_index& index);
+ void create_one_off_subaddress(const cryptonote::subaddress_index& index);
std::string get_subaddress_label(const cryptonote::subaddress_index& index) const;
void set_subaddress_label(const cryptonote::subaddress_index &index, const std::string &label);
void set_subaddress_lookahead(size_t major, size_t minor);
@@ -1318,25 +1332,25 @@ private:
crypto::public_key get_multisig_signing_public_key(const crypto::secret_key &skey) const;
template<class t_request, class t_response>
- inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
+ inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST")
{
if (m_offline) return false;
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
- return epee::net_utils::invoke_http_json(uri, req, res, m_http_client, timeout, http_method);
+ return epee::net_utils::invoke_http_json(uri, req, res, *m_http_client, timeout, http_method);
}
template<class t_request, class t_response>
- inline bool invoke_http_bin(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
+ inline bool invoke_http_bin(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST")
{
if (m_offline) return false;
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
- return epee::net_utils::invoke_http_bin(uri, req, res, m_http_client, timeout, http_method);
+ return epee::net_utils::invoke_http_bin(uri, req, res, *m_http_client, timeout, http_method);
}
template<class t_request, class t_response>
- inline bool invoke_http_json_rpc(const boost::string_ref uri, const std::string& method_name, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
+ inline bool invoke_http_json_rpc(const boost::string_ref uri, const std::string& method_name, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
{
if (m_offline) return false;
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
- return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id);
+ return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, *m_http_client, timeout, http_method, req_id);
}
bool set_ring_database(const std::string &filename);
@@ -1402,11 +1416,18 @@ private:
*/
bool store_keys(const std::string& keys_file_name, const epee::wipeable_string& password, bool watch_only = false);
/*!
- * \brief Load wallet information from wallet file.
+ * \brief Load wallet keys information from wallet file.
* \param keys_file_name Name of wallet file
* \param password Password of wallet file
*/
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
+ /*!
+ * \brief Load wallet keys information from a string buffer.
+ * \param keys_buf Keys buffer to load
+ * \param password Password of keys buffer
+ */
+ bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password);
+ bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password, boost::optional<crypto::chacha_key>& keys_to_encrypt);
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
bool should_skip_block(const cryptonote::block &b, uint64_t height) const;
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
@@ -1501,7 +1522,7 @@ private:
std::string m_wallet_file;
std::string m_keys_file;
std::string m_mms_file;
- epee::net_utils::http::http_simple_client m_http_client;
+ const std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client;
hashchain m_blockchain;
std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
diff --git a/src/wallet/wallet_rpc_payments.cpp b/src/wallet/wallet_rpc_payments.cpp
index 41696d13b..4f5364269 100644
--- a/src/wallet/wallet_rpc_payments.cpp
+++ b/src/wallet/wallet_rpc_payments.cpp
@@ -85,7 +85,7 @@ bool wallet2::make_rpc_payment(uint32_t nonce, uint32_t cookie, uint64_t &credit
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
epee::json_rpc::error error;
- bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", "rpc_access_submit_nonce", req, res, error, m_http_client, rpc_timeout);
+ bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", "rpc_access_submit_nonce", req, res, error, *m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, error, res, "rpc_access_submit_nonce");
THROW_WALLET_EXCEPTION_IF(res.credits < pre_call_credits, error::wallet_internal_error, "RPC payment did not increase balance");