aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/CMakeLists.txt2
-rw-r--r--src/wallet/api/address_book.cpp4
-rw-r--r--src/wallet/api/address_book.h2
-rw-r--r--src/wallet/api/pending_transaction.cpp4
-rw-r--r--src/wallet/api/pending_transaction.h2
-rw-r--r--src/wallet/api/transaction_history.cpp2
-rw-r--r--src/wallet/api/transaction_history.h2
-rw-r--r--src/wallet/api/transaction_info.cpp2
-rw-r--r--src/wallet/api/transaction_info.h2
-rw-r--r--src/wallet/api/unsigned_transaction.h2
-rw-r--r--src/wallet/api/utils.cpp2
-rw-r--r--src/wallet/api/wallet.cpp24
-rw-r--r--src/wallet/api/wallet.h5
-rw-r--r--src/wallet/api/wallet_manager.cpp36
-rw-r--r--src/wallet/api/wallet_manager.h4
-rw-r--r--src/wallet/node_rpc_proxy.cpp43
-rw-r--r--src/wallet/node_rpc_proxy.h4
-rw-r--r--src/wallet/wallet2.cpp293
-rw-r--r--src/wallet/wallet2.h46
-rw-r--r--src/wallet/wallet2_api.h9
-rw-r--r--src/wallet/wallet_args.cpp54
-rw-r--r--src/wallet/wallet_args.h4
-rw-r--r--src/wallet/wallet_errors.h2
-rw-r--r--src/wallet/wallet_rpc_server.cpp98
-rw-r--r--src/wallet/wallet_rpc_server.h5
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h25
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h2
27 files changed, 490 insertions, 190 deletions
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 3c103bc29..aed021b9c 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2016, The Monero Project
+# Copyright (c) 2014-2017, The Monero Project
#
# All rights reserved.
#
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index e397dac04..28f835ebd 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -180,4 +180,4 @@ AddressBookImpl::~AddressBookImpl()
} // namespace
-namespace Bitmonero = Monero; \ No newline at end of file
+namespace Bitmonero = Monero;
diff --git a/src/wallet/api/address_book.h b/src/wallet/api/address_book.h
index 5f72c5860..25f59128b 100644
--- a/src/wallet/api/address_book.h
+++ b/src/wallet/api/address_book.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index 09010a688..9798d66c6 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -124,7 +124,7 @@ bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite)
m_errorString = writer.str();
if (!reason.empty())
m_errorString += string(tr(". Reason: ")) + reason;
- } catch (std::exception &e) {
+ } catch (const std::exception &e) {
m_errorString = string(tr("Unknown exception: ")) + e.what();
m_status = Status_Error;
} catch (...) {
diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h
index d85a686fd..0c3e95a85 100644
--- a/src/wallet/api/pending_transaction.h
+++ b/src/wallet/api/pending_transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
index 1e50652c6..85f2b05ce 100644
--- a/src/wallet/api/transaction_history.cpp
+++ b/src/wallet/api/transaction_history.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h
index 37c9ea0e4..4987bdab2 100644
--- a/src/wallet/api/transaction_history.h
+++ b/src/wallet/api/transaction_history.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp
index 576ae8532..79a8fe9b5 100644
--- a/src/wallet/api/transaction_info.cpp
+++ b/src/wallet/api/transaction_info.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h
index af9696daf..16fa5da7a 100644
--- a/src/wallet/api/transaction_info.h
+++ b/src/wallet/api/transaction_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/unsigned_transaction.h b/src/wallet/api/unsigned_transaction.h
index 8038334e4..9c442f503 100644
--- a/src/wallet/api/unsigned_transaction.h
+++ b/src/wallet/api/unsigned_transaction.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp
index c369427b4..a9646e038 100644
--- a/src/wallet/api/utils.cpp
+++ b/src/wallet/api/utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index aeff2b943..d5c2fbda2 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -99,10 +99,10 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, uint64_t amount)
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount)
{
- std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx));
+ std::string tx_hash = epee::string_tools::pod_to_hex(txid);
LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height
<< ", tx: " << tx_hash
@@ -114,10 +114,10 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_unconfirmed_money_received(uint64_t height, const cryptonote::transaction& tx, uint64_t amount)
+ virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount)
{
- std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx));
+ std::string tx_hash = epee::string_tools::pod_to_hex(txid);
LOG_PRINT_L3(__FUNCTION__ << ": unconfirmed money received. height: " << height
<< ", tx: " << tx_hash
@@ -129,11 +129,11 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, uint64_t amount,
+ virtual void on_money_spent(uint64_t height, const crypto::hash &txid, uint64_t amount,
const cryptonote::transaction& spend_tx)
{
// TODO;
- std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx));
+ std::string tx_hash = epee::string_tools::pod_to_hex(txid);
LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height
<< ", tx: " << tx_hash
<< ", amount: " << print_money(amount));
@@ -144,7 +144,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx)
+ virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid)
{
// TODO;
}
@@ -656,9 +656,11 @@ string WalletImpl::keysFilename() const
return m_wallet->get_keys_file();
}
-bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit)
+bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit, const std::string &daemon_username, const std::string &daemon_password)
{
clearStatus();
+ if(daemon_username != "")
+ m_daemon_login.emplace(daemon_username, daemon_password);
return doInit(daemon_address, upper_transaction_size_limit);
}
@@ -831,7 +833,7 @@ bool WalletImpl::exportKeyImages(const string &filename)
return false;
}
}
- catch (std::exception &e)
+ catch (const std::exception &e)
{
LOG_ERROR("Error exporting key images: " << e.what());
m_errorString = e.what();
@@ -1365,7 +1367,7 @@ bool WalletImpl::isNewWallet() const
bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit)
{
- if (!m_wallet->init(daemon_address, boost::none, upper_transaction_size_limit))
+ if (!m_wallet->init(daemon_address, m_daemon_login, upper_transaction_size_limit))
return false;
// in case new wallet, this will force fast-refresh (pulling hashes instead of blocks)
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 3994afaa3..456110908 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -78,7 +78,7 @@ public:
bool store(const std::string &path);
std::string filename() const;
std::string keysFilename() const;
- bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0);
+ bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "");
bool connectToDaemon();
ConnectionStatus connected() const;
void setTrustedDaemon(bool arg);
@@ -170,6 +170,7 @@ private:
std::atomic<bool> m_rebuildWalletCache;
// cache connection status to avoid unnecessary RPC calls
mutable std::atomic<bool> m_is_connected;
+ boost::optional<epee::net_utils::http::login> m_daemon_login{};
};
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 253de19d2..8e86c87b3 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -33,11 +33,16 @@
#include "wallet.h"
#include "common_defines.h"
#include "common/dns_utils.h"
+#include "common/util.h"
+#include "common/updates.h"
+#include "version.h"
#include "net/http_client.h"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "WalletAPI"
namespace epee {
unsigned int g_test_dbg_lock_sleep = 0;
@@ -412,13 +417,15 @@ bool WalletManagerImpl::isMining() const
return mres.active;
}
-bool WalletManagerImpl::startMining(const std::string &address, uint32_t threads)
+bool WalletManagerImpl::startMining(const std::string &address, uint32_t threads, bool background_mining, bool ignore_battery)
{
cryptonote::COMMAND_RPC_START_MINING::request mreq;
cryptonote::COMMAND_RPC_START_MINING::response mres;
mreq.miner_address = address;
mreq.threads_count = threads;
+ mreq.ignore_battery = ignore_battery;
+ mreq.do_background_mining = background_mining;
if (!connect_and_invoke(m_daemonAddress, "/start_mining", mreq, mres))
return false;
@@ -443,6 +450,29 @@ std::string WalletManagerImpl::resolveOpenAlias(const std::string &address, bool
return addresses.front();
}
+std::tuple<bool, std::string, std::string, std::string, std::string> WalletManager::checkUpdates(const std::string &software, const std::string &subdir)
+{
+#ifdef BUILD_TAG
+ static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
+#else
+ static const char buildtag[] = "source";
+#endif
+
+ std::string version, hash;
+ MDEBUG("Checking for a new " << software << " version for " << buildtag);
+ if (!tools::check_updates(software, buildtag, version, hash))
+ return std::make_tuple(false, "", "", "", "");
+
+ if (tools::vercmp(version.c_str(), MONERO_VERSION) > 0)
+ {
+ std::string user_url = tools::get_update_url(software, subdir, buildtag, version, true);
+ std::string auto_url = tools::get_update_url(software, subdir, buildtag, version, false);
+ MGINFO("Version " << version << " of " << software << " for " << buildtag << " is available: " << user_url << ", SHA256 hash " << hash);
+ return std::make_tuple(true, version, hash, user_url, auto_url);
+ }
+ return std::make_tuple(false, "", "", "", "");
+}
+
///////////////////// WalletManagerFactory implementation //////////////////////
WalletManager *WalletManagerFactory::getWalletManager()
@@ -464,7 +494,7 @@ void WalletManagerFactory::setLogLevel(int level)
void WalletManagerFactory::setLogCategories(const std::string &categories)
{
- mlog_set_categories(categories.c_str());
+ mlog_set_log(categories.c_str());
}
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index ce9b70e96..677c105fb 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -62,7 +62,7 @@ public:
void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const;
uint64_t blockTarget() const;
bool isMining() const;
- bool startMining(const std::string &address, uint32_t threads = 1);
+ bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true);
bool stopMining();
std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const;
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index cc249b5cc..03e1bbd98 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -36,6 +36,8 @@ using namespace epee;
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, boost::mutex &mutex)
: m_http_client(http_client)
, m_daemon_rpc_mutex(mutex)
@@ -45,8 +47,43 @@ NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_clien
, m_dynamic_per_kb_fee_estimate(0)
, m_dynamic_per_kb_fee_estimate_cached_height(0)
, m_dynamic_per_kb_fee_estimate_grace_blocks(0)
+ , m_rpc_version(0)
{}
+void NodeRPCProxy::invalidate()
+{
+ m_height = 0;
+ m_height_time = 0;
+ for (size_t n = 0; n < 256; ++n)
+ m_earliest_height[n] = 0;
+ m_dynamic_per_kb_fee_estimate = 0;
+ m_dynamic_per_kb_fee_estimate_cached_height = 0;
+ m_dynamic_per_kb_fee_estimate_grace_blocks = 0;
+ m_rpc_version = 0;
+}
+
+boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version)
+{
+ const time_t now = time(NULL);
+ if (m_rpc_version == 0)
+ {
+ 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);
+ req_t.jsonrpc = "2.0";
+ req_t.id = epee::serialization::storage_entry(0);
+ req_t.method = "get_version";
+ m_daemon_rpc_mutex.lock();
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+ CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.result.status == CORE_RPC_STATUS_OK, resp_t.result.status, "Failed to get daemon RPC version");
+ m_rpc_version = resp_t.result.version;
+ }
+ rpc_version = m_rpc_version;
+ return boost::optional<std::string>();
+}
+
boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height)
{
const time_t now = time(NULL);
@@ -56,7 +93,7 @@ boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height)
cryptonote::COMMAND_RPC_GET_HEIGHT::response res = AUTO_VAL_INIT(res);
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json("/getheight", req, res, m_http_client);
+ bool r = net_utils::invoke_http_json("/getheight", req, res, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, res.status, "Failed to connect to daemon");
@@ -85,7 +122,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version,
req_t.id = epee::serialization::storage_entry(0);
req_t.method = "hard_fork_info";
req_t.params.version = version;
- bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client);
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon");
@@ -115,7 +152,7 @@ boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint6
req_t.id = epee::serialization::storage_entry(0);
req_t.method = "get_fee_estimate";
req_t.params.grace_blocks = grace_blocks;
- bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client);
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon");
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index e2f42d541..02d1d8d93 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -41,6 +41,9 @@ class NodeRPCProxy
public:
NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex);
+ void invalidate();
+
+ boost::optional<std::string> get_rpc_version(uint32_t &version);
boost::optional<std::string> get_height(uint64_t &height);
void set_height(uint64_t h);
boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height);
@@ -56,6 +59,7 @@ private:
uint64_t m_dynamic_per_kb_fee_estimate;
uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
+ uint32_t m_rpc_version;
};
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 56eee6ecf..dce1ee9de 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -452,10 +452,10 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.restricted);
}
-boost::optional<password_container> wallet2::password_prompt(const bool is_new_wallet)
+boost::optional<password_container> wallet2::password_prompt(const bool new_password)
{
auto pwd_container = tools::password_container::prompt(
- is_new_wallet, (is_new_wallet ? tr("Enter a password for your new wallet") : tr("Wallet password"))
+ new_password, (new_password ? tr("Enter new wallet password") : tr("Wallet password"))
);
if (!pwd_container)
{
@@ -633,28 +633,13 @@ bool wallet2::wallet_generate_key_image_helper(const cryptonote::account_keys& a
return true;
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_transaction(const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool)
+void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool)
{
- class lazy_txid_getter
- {
- const cryptonote::transaction &tx;
- crypto::hash lazy_txid;
- bool computed;
- public:
- lazy_txid_getter(const transaction &tx): tx(tx), computed(false) {}
- const crypto::hash &operator()()
- {
- if (!computed)
- {
- lazy_txid = cryptonote::get_transaction_hash(tx);
- computed = true;
- }
- return lazy_txid;
- }
- } txid(tx);
+ // In this function, tx (probably) only contains the base information
+ // (that is, the prunable stuff may or may not be included)
if (!miner_tx)
- process_unconfirmed(tx, height);
+ process_unconfirmed(txid, tx, height);
std::vector<size_t> outs;
uint64_t tx_money_got_in_outs = 0;
crypto::public_key tx_pub_key = null_pkey;
@@ -663,7 +648,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
if(!parse_tx_extra(tx.extra, tx_extra_fields))
{
// Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
- LOG_PRINT_L0("Transaction extra has unsupported format: " << txid());
+ LOG_PRINT_L0("Transaction extra has unsupported format: " << txid);
}
// Don't try to extract tx public key if tx has no ouputs
@@ -677,9 +662,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
{
if (pk_index > 1)
break;
- LOG_PRINT_L0("Public key wasn't found in the transaction extra. Skipping transaction " << txid());
+ LOG_PRINT_L0("Public key wasn't found in the transaction extra. Skipping transaction " << txid);
if(0 != m_callback)
- m_callback->on_skip_transaction(height, tx);
+ m_callback->on_skip_transaction(height, txid, tx);
return;
}
@@ -879,7 +864,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
td.m_internal_output_index = o;
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
- td.m_txid = txid();
+ td.m_txid = txid;
td.m_key_image = ki[o];
td.m_key_image_known = !m_watch_only;
td.m_amount = tx.vout[o].amount;
@@ -903,9 +888,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
set_unspent(m_transfers.size()-1);
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[in_ephemeral[o].pub] = m_transfers.size()-1;
- LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid());
+ LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
- m_callback->on_money_received(height, tx, td.m_amount);
+ m_callback->on_money_received(height, txid, tx, td.m_amount);
}
}
else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx.vout[o].amount)
@@ -930,7 +915,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
td.m_internal_output_index = o;
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
- td.m_txid = txid();
+ td.m_txid = txid;
td.m_amount = tx.vout[o].amount;
td.m_pk_index = pk_index - 1;
if (td.m_amount == 0)
@@ -952,9 +937,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
THROW_WALLET_EXCEPTION_IF(td.get_public_key() != in_ephemeral[o].pub, error::wallet_internal_error, "Inconsistent public keys");
THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status");
- LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid());
+ LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
- m_callback->on_money_received(height, tx, td.m_amount);
+ m_callback->on_money_received(height, txid, tx, td.m_amount);
}
}
}
@@ -982,17 +967,17 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
tx_money_spent_in_ins += amount;
if (!pool)
{
- LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid());
+ LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid);
set_spent(it->second, height);
if (0 != m_callback)
- m_callback->on_money_spent(height, tx, amount, tx);
+ m_callback->on_money_spent(height, txid, tx, amount, tx);
}
}
}
if (tx_money_spent_in_ins > 0)
{
- process_outgoing(tx, height, ts, tx_money_spent_in_ins, tx_money_got_in_outs);
+ process_outgoing(txid, tx, height, ts, tx_money_spent_in_ins, tx_money_got_in_outs);
}
uint64_t received = (tx_money_spent_in_ins < tx_money_got_in_outs) ? tx_money_got_in_outs - tx_money_spent_in_ins : 0;
@@ -1038,7 +1023,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
}
payment_details payment;
- payment.m_tx_hash = txid();
+ payment.m_tx_hash = txid;
payment.m_amount = received;
payment.m_block_height = height;
payment.m_unlock_time = tx.unlock_time;
@@ -1046,7 +1031,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
if (pool) {
m_unconfirmed_payments.emplace(payment_id, payment);
if (0 != m_callback)
- m_callback->on_unconfirmed_money_received(height, tx, payment.m_amount);
+ m_callback->on_unconfirmed_money_received(height, txid, tx, payment.m_amount);
}
else
m_payments.emplace(payment_id, payment);
@@ -1054,12 +1039,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_unconfirmed(const cryptonote::transaction& tx, uint64_t height)
+void wallet2::process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height)
{
if (m_unconfirmed_txs.empty())
return;
- crypto::hash txid = get_transaction_hash(tx);
auto unconf_it = m_unconfirmed_txs.find(txid);
if(unconf_it != m_unconfirmed_txs.end()) {
if (store_tx_info()) {
@@ -1075,9 +1059,8 @@ void wallet2::process_unconfirmed(const cryptonote::transaction& tx, uint64_t he
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_outgoing(const cryptonote::transaction &tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received)
+void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::transaction &tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received)
{
- crypto::hash txid = get_transaction_hash(tx);
std::pair<std::unordered_map<crypto::hash, confirmed_transfer_details>::iterator, bool> entry = m_confirmed_txs.insert(std::make_pair(txid, confirmed_transfer_details()));
// fill with the info we know, some info might already be there
if (entry.second)
@@ -1120,16 +1103,19 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
if(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height)
{
TIME_MEASURE_START(miner_tx_handle_time);
- process_new_transaction(b.miner_tx, o_indices.indices[txidx++].indices, height, b.timestamp, true, false);
+ process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, o_indices.indices[txidx++].indices, height, b.timestamp, true, false);
TIME_MEASURE_FINISH(miner_tx_handle_time);
TIME_MEASURE_START(txs_handle_time);
- for(auto& txblob: bche.txs)
+ THROW_WALLET_EXCEPTION_IF(bche.txs.size() != b.tx_hashes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
+ size_t idx = 0;
+ for (const auto& txblob: bche.txs)
{
cryptonote::transaction tx;
- bool r = parse_and_validate_tx_from_blob(txblob, tx);
+ bool r = parse_and_validate_tx_base_from_blob(txblob, tx);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_parse_error, txblob);
- process_new_transaction(tx, o_indices.indices[txidx++].indices, height, b.timestamp, false, false);
+ process_new_transaction(b.tx_hashes[idx], tx, o_indices.indices[txidx++].indices, height, b.timestamp, false, false);
+ ++idx;
}
TIME_MEASURE_FINISH(txs_handle_time);
LOG_PRINT_L2("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms");
@@ -1185,6 +1171,34 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
req.block_ids = short_chain_history;
+ uint32_t rpc_version;
+ boost::optional<std::string> result = m_node_rpc_proxy.get_rpc_version(rpc_version);
+ // no error
+ if (!!result)
+ {
+ // empty string -> not connection
+ THROW_WALLET_EXCEPTION_IF(result->empty(), tools::error::no_connection_to_daemon, "getversion");
+ THROW_WALLET_EXCEPTION_IF(*result == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, "getversion");
+ if (*result != CORE_RPC_STATUS_OK)
+ {
+ MDEBUG("Cannot determined daemon RPC version, not asking for pruned blocks");
+ req.prune = false; // old daemon
+ }
+ }
+ else
+ {
+ if (rpc_version >= MAKE_CORE_RPC_VERSION(1, 7))
+ {
+ MDEBUG("Daemon is recent enough, asking for pruned blocks");
+ req.prune = true;
+ }
+ else
+ {
+ MDEBUG("Daemon is too old, not asking for pruned blocks");
+ req.prune = false;
+ }
+ }
+
req.start_height = start_height;
m_daemon_rpc_mutex.lock();
bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, m_http_client, rpc_timeout);
@@ -1367,6 +1381,8 @@ void wallet2::pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_hei
//----------------------------------------------------------------------------------------------------
void wallet2::update_pool_state()
{
+ MDEBUG("update_pool_state start");
+
// get the pool state
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res;
@@ -1376,6 +1392,7 @@ void wallet2::update_pool_state()
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
+ MDEBUG("update_pool_state got pool");
// remove any pending tx that's not in the pool
std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin();
@@ -1430,6 +1447,7 @@ void wallet2::update_pool_state()
}
}
}
+ MDEBUG("update_pool_state done first loop");
// remove pool txes to us that aren't in the pool anymore
std::unordered_map<crypto::hash, wallet2::payment_details>::iterator uit = m_unconfirmed_payments.begin();
@@ -1451,6 +1469,7 @@ void wallet2::update_pool_state()
m_unconfirmed_payments.erase(pit);
}
}
+ MDEBUG("update_pool_state done second loop");
// add new pool txes to us
for (auto it: res.transactions)
@@ -1459,6 +1478,11 @@ void wallet2::update_pool_state()
if(epee::string_tools::parse_hexstr_to_binbuff(it.id_hash, txid_data) && txid_data.size() == sizeof(crypto::hash))
{
const crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+ if (m_scanned_pool_txs[0].find(txid) != m_scanned_pool_txs[0].end() || m_scanned_pool_txs[1].find(txid) != m_scanned_pool_txs[1].end())
+ {
+ LOG_PRINT_L2("Already seen " << txid << ", skipped");
+ continue;
+ }
if (m_unconfirmed_payments.find(txid) == m_unconfirmed_payments.end())
{
LOG_PRINT_L1("Found new pool tx: " << txid);
@@ -1477,9 +1501,11 @@ void wallet2::update_pool_state()
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
req.txs_hashes.push_back(it.id_hash);
+ MDEBUG("asking for " << it.id_hash);
req.decode_as_json = false;
m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ MDEBUG("asked for " << it.id_hash << ", got " << r << " and " << res.status);
m_daemon_rpc_mutex.unlock();
if (r && res.status == CORE_RPC_STATUS_OK)
{
@@ -1497,7 +1523,13 @@ void wallet2::update_pool_state()
{
if (tx_hash == txid)
{
- process_new_transaction(tx, std::vector<uint64_t>(), 0, time(NULL), false, true);
+ process_new_transaction(txid, tx, std::vector<uint64_t>(), 0, time(NULL), false, true);
+ m_scanned_pool_txs[0].insert(txid);
+ if (m_scanned_pool_txs[0].size() > 5000)
+ {
+ std::swap(m_scanned_pool_txs[0], m_scanned_pool_txs[1]);
+ m_scanned_pool_txs[0].clear();
+ }
}
else
{
@@ -1536,7 +1568,7 @@ void wallet2::update_pool_state()
}
else
{
- LOG_PRINT_L1("Already saw that one");
+ LOG_PRINT_L1("Already saw that one, it's for us");
}
}
else
@@ -1544,6 +1576,7 @@ void wallet2::update_pool_state()
LOG_PRINT_L0("Failed to parse txid");
}
}
+ MDEBUG("update_pool_state end");
}
//----------------------------------------------------------------------------------------------------
void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history)
@@ -1880,6 +1913,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p
value2.SetInt(m_ask_password ? 1 :0);
json.AddMember("ask_password", value2, json.GetAllocator());
+ value2.SetInt(cryptonote::get_default_decimal_point());
+ json.AddMember("default_decimal_point", value2, json.GetAllocator());
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -2010,6 +2046,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
m_confirm_missing_payment_id = field_confirm_missing_payment_id;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ask_password, int, Int, false, true);
m_ask_password = field_ask_password;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_decimal_point, int, Int, false, CRYPTONOTE_DISPLAY_DECIMAL_POINT);
+ cryptonote::set_default_decimal_point(field_default_decimal_point);
}
const cryptonote::account_keys& keys = m_account.get_keys();
@@ -2274,6 +2312,16 @@ bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash&
return false;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::set_default_decimal_point(unsigned int decimal_point)
+{
+ cryptonote::set_default_decimal_point(decimal_point);
+}
+//----------------------------------------------------------------------------------------------------
+unsigned int wallet2::get_default_decimal_point() const
+{
+ return cryptonote::get_default_decimal_point();
+}
+//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_file_names(const std::string& file_path)
{
do_prepare_file_names(file_path, m_keys_file, m_wallet_file);
@@ -2286,6 +2334,7 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
if(!m_http_client.is_connected())
{
+ m_node_rpc_proxy.invalidate();
if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
return false;
}
@@ -2298,7 +2347,11 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
req_t.id = epee::serialization::storage_entry(0);
req_t.method = "get_version";
bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client);
- if (!r || resp_t.result.status != CORE_RPC_STATUS_OK)
+ if(!r) {
+ *version = 0;
+ return false;
+ }
+ if (resp_t.result.status != CORE_RPC_STATUS_OK)
*version = 0;
else
*version = resp_t.result.version;
@@ -2605,28 +2658,31 @@ void wallet2::get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2:
//----------------------------------------------------------------------------------------------------
void wallet2::rescan_spent()
{
- std::vector<std::string> key_images;
-
- // make a list of key images for all our outputs
- for (size_t i = 0; i < m_transfers.size(); ++i)
- {
- const transfer_details& td = m_transfers[i];
- key_images.push_back(string_tools::pod_to_hex(td.m_key_image));
+ // This is RPC call that can take a long time if there are many outputs,
+ // so we call it several times, in stripes, so we don't time out spuriously
+ std::vector<int> spent_status;
+ spent_status.reserve(m_transfers.size());
+ const size_t chunk_size = 1000;
+ for (size_t start_offset = 0; start_offset < m_transfers.size(); start_offset += chunk_size)
+ {
+ const size_t n_outputs = std::min<size_t>(chunk_size, m_transfers.size() - start_offset);
+ MDEBUG("Calling is_key_image_spent on " << start_offset << " - " << (start_offset + n_outputs - 1) << ", out of " << m_transfers.size());
+ COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
+ COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
+ for (size_t n = start_offset; n < start_offset + n_outputs; ++n)
+ req.key_images.push_back(string_tools::pod_to_hex(m_transfers[n].m_key_image));
+ m_daemon_rpc_mutex.lock();
+ bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+ THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, 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 = " +
+ std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(n_outputs));
+ std::copy(daemon_resp.spent_status.begin(), daemon_resp.spent_status.end(), std::back_inserter(spent_status));
}
- COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
- COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
- req.key_images = key_images;
- m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
- m_daemon_rpc_mutex.unlock();
- THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
- THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != key_images.size(), error::wallet_internal_error,
- "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
- std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(key_images.size()));
-
// update spent status
for (size_t i = 0; i < m_transfers.size(); ++i)
{
@@ -2634,7 +2690,7 @@ void wallet2::rescan_spent()
// a view wallet may not know about key images
if (!td.m_key_image_known)
continue;
- if (td.m_spent != (daemon_resp.spent_status[i] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT))
+ if (td.m_spent != (spent_status[i] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT))
{
if (td.m_spent)
{
@@ -3286,20 +3342,35 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return true;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::get_fee_multiplier(uint32_t priority, bool use_new_fee) const
+uint64_t wallet2::get_fee_multiplier(uint32_t priority, int fee_algorithm) const
{
static const uint64_t old_multipliers[3] = {1, 2, 3};
static const uint64_t new_multipliers[3] = {1, 20, 166};
+ static const uint64_t newer_multipliers[4] = {1, 4, 20, 166};
- // 0 -> default (here, x1)
+ // 0 -> default (here, x1 till fee algorithm 2, x4 from it)
if (priority == 0)
priority = m_default_priority;
if (priority == 0)
- priority = 1;
+ {
+ if (fee_algorithm >= 2)
+ priority = 2;
+ else
+ priority = 1;
+ }
- // 1 to 3 are allowed as priorities
- if (priority >= 1 && priority <= 3)
- return (use_new_fee ? new_multipliers : old_multipliers)[priority-1];
+ // 1 to 3/4 are allowed as priorities
+ uint32_t max_priority = (fee_algorithm >= 2) ? 4 : 3;
+ if (priority >= 1 && priority <= max_priority)
+ {
+ switch (fee_algorithm)
+ {
+ case 0: return old_multipliers[priority-1];
+ case 1: return new_multipliers[priority-1];
+ case 2: return newer_multipliers[priority-1];
+ default: THROW_WALLET_EXCEPTION_IF (true, error::invalid_priority);
+ }
+ }
THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority);
return 1;
@@ -3324,6 +3395,16 @@ uint64_t wallet2::get_per_kb_fee()
return get_dynamic_per_kb_fee_estimate();
}
//----------------------------------------------------------------------------------------------------
+int wallet2::get_fee_algorithm()
+{
+ // changes at v3 and v5
+ if (use_fork_rules(5, 0))
+ return 2;
+ if (use_fork_rules(3, -720 * 14))
+ return 1;
+ return 0;
+}
+//----------------------------------------------------------------------------------------------------
// separated the call(s) to wallet2::transfer into their own function
//
// this function will make multiple calls to wallet2::transfer if multiple
@@ -3332,9 +3413,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
{
const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon);
- const bool use_new_fee = use_fork_rules(3, -720 * 14);
const uint64_t fee_per_kb = get_per_kb_fee();
- const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
+ const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
// failsafe split attempt counter
size_t attempt_count = 0;
@@ -3453,7 +3533,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
req_t.params.amounts.resize(std::distance(req_t.params.amounts.begin(), end));
req_t.params.unlocked = true;
req_t.params.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE;
- bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client);
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -4059,7 +4139,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money) co
return picks;
}
-static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices)
+bool wallet2::should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const
{
if (!use_rct)
return false;
@@ -4067,9 +4147,43 @@ static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const
return false;
if (unused_dust_indices.empty() && unused_transfers_indices.empty())
return false;
+ // we want at least one free rct output to avoid a corner case where
+ // we'd choose a non rct output which doesn't have enough "siblings"
+ // value-wise on the chain, and thus can't be mixed
+ bool found = false;
+ for (auto i: unused_dust_indices)
+ {
+ if (m_transfers[i].is_rct())
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found) for (auto i: unused_transfers_indices)
+ {
+ if (m_transfers[i].is_rct())
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
return true;
}
+std::vector<size_t> wallet2::get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const
+{
+ std::vector<size_t> indices;
+ for (size_t n: unused_dust_indices)
+ if (m_transfers[n].is_rct())
+ indices.push_back(n);
+ for (size_t n: unused_transfers_indices)
+ if (m_transfers[n].is_rct())
+ indices.push_back(n);
+ return indices;
+}
+
// Another implementation of transaction creation that is hopefully better
// While there is anything left to pay, it goes through random outputs and tries
// to fill the next destination/amount. If it fully fills it, it will use the
@@ -4113,9 +4227,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
const bool use_rct = use_fork_rules(4, 0);
- const bool use_new_fee = use_fork_rules(3, -720 * 14);
const uint64_t fee_per_kb = get_per_kb_fee();
- const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
+ const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
// throw if attempting a transaction with no destinations
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
@@ -4135,8 +4248,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
// gather all our dust and non dust outputs
- const std::vector<size_t> unused_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon);
- for (size_t i: unused_indices)
+ for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
@@ -4219,7 +4331,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
size_t idx;
if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee) {
// the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
- idx = pop_best_value(unused_dust_indices.empty() ? unused_transfers_indices : unused_dust_indices, tx.selected_transfers, true);
+ std::vector<size_t> indices = get_only_rct(unused_dust_indices, unused_transfers_indices);
+ idx = pop_best_value(indices, tx.selected_transfers, true);
// since we're trying to add a second output which is not strictly needed,
// we only add it if it's unrelated enough to the first one
@@ -4229,6 +4342,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Second outout was not strictly needed, and relatedness " << relatedness << ", not adding");
break;
}
+ pop_if_present(unused_transfers_indices, idx);
+ pop_if_present(unused_dust_indices, idx);
} else if (!prefered_inputs.empty()) {
idx = pop_back(prefered_inputs);
pop_if_present(unused_transfers_indices, idx);
@@ -4440,9 +4555,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
std::vector<std::vector<get_outs_entry>> outs;
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
- const bool use_new_fee = use_fork_rules(3, -720 * 14);
const uint64_t fee_per_kb = get_per_kb_fee();
- const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
+ const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs");
@@ -4603,7 +4717,7 @@ uint64_t wallet2::get_upper_tranaction_size_limit()
{
if (m_upper_transaction_size_limit > 0)
return m_upper_transaction_size_limit;
- uint64_t full_reward_zone = use_fork_rules(2, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
+ uint64_t full_reward_zone = use_fork_rules(5, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : use_fork_rules(2, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
}
//----------------------------------------------------------------------------------------------------
@@ -4653,7 +4767,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
req_t.params.min_count = count;
req_t.params.max_count = 0;
req_t.params.unlocked = unlocked;
- bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client);
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_outputs_from_histogram");
THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -4692,7 +4806,7 @@ uint64_t wallet2::get_num_rct_outputs()
req_t.params.amounts.push_back(0);
req_t.params.min_count = 0;
req_t.params.max_count = 0;
- bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client);
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs");
THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -4729,7 +4843,6 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2
tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD);
- const bool use_new_fee = use_fork_rules(3, -720 * 14);
const uint64_t fee_per_kb = get_per_kb_fee();
// may throw
@@ -5424,7 +5537,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
height_mid,
height_max
};
- bool r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, m_http_client);
+ bool 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)
{
std::ostringstream oss;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index dba9a400d..565cd9870 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -70,10 +70,10 @@ namespace tools
{
public:
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
- virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, uint64_t amount) {}
- virtual void on_unconfirmed_money_received(uint64_t height, const cryptonote::transaction& tx, uint64_t amount) {}
- virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx) {}
- virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) {}
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount) {}
+ virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount) {}
+ virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx) {}
+ virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) {}
virtual ~i_wallet2_callback() {}
};
@@ -114,7 +114,7 @@ namespace tools
static void init_options(boost::program_options::options_description& desc_params);
//! \return Password retrieved from prompt. Logs error on failure.
- static boost::optional<password_container> password_prompt(const bool is_new_wallet);
+ static boost::optional<password_container> password_prompt(const bool new_password);
//! Uses stdin and stdout. Returns a wallet2 if no errors.
static std::unique_ptr<wallet2> make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file);
@@ -456,7 +456,14 @@ namespace tools
a & m_tx_notes;
if(ver < 13)
return;
- a & m_unconfirmed_payments;
+ if (ver < 17)
+ {
+ // we're loading an old version, where m_unconfirmed_payments was a std::map
+ std::unordered_map<crypto::hash, payment_details> m;
+ a & m;
+ for (std::unordered_map<crypto::hash, payment_details>::const_iterator i = m.begin(); i != m.end(); ++i)
+ m_unconfirmed_payments.insert(*i);
+ }
if(ver < 14)
return;
if(ver < 15)
@@ -475,6 +482,13 @@ namespace tools
if(ver < 16)
return;
a & m_address_book;
+ if(ver < 17)
+ return;
+ a & m_unconfirmed_payments;
+ if(ver < 18)
+ return;
+ a & m_scanned_pool_txs[0];
+ a & m_scanned_pool_txs[1];
}
/*!
@@ -510,6 +524,8 @@ namespace tools
void confirm_missing_payment_id(bool always) { m_confirm_missing_payment_id = always; }
bool ask_password() const { return m_ask_password; }
void ask_password(bool always) { m_ask_password = always; }
+ void set_default_decimal_point(unsigned int decimal_point);
+ unsigned int get_default_decimal_point() const;
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const;
@@ -525,6 +541,7 @@ namespace tools
void get_hard_fork_info(uint8_t version, uint64_t &earliest_height);
bool use_fork_rules(uint8_t version, int64_t early_blocks = 0);
+ int get_fee_algorithm();
std::string get_wallet_file() const;
std::string get_keys_file() const;
@@ -585,7 +602,7 @@ namespace tools
* \param password Password of wallet file
*/
bool load_keys(const std::string& keys_file_name, const std::string& password);
- void process_new_transaction(const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool);
+ void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool);
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const crypto::hash& bl_id, uint64_t height, const cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices &o_indices);
void detach_blockchain(uint64_t height);
void get_short_chain_history(std::list<crypto::hash>& ids) const;
@@ -598,8 +615,8 @@ namespace tools
void process_blocks(uint64_t start_height, const std::list<cryptonote::block_complete_entry> &blocks, const std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices, uint64_t& blocks_added);
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::list<size_t>& selected_transfers, bool trusted_daemon);
bool prepare_file_names(const std::string& file_path);
- void process_unconfirmed(const cryptonote::transaction& tx, uint64_t height);
- void process_outgoing(const cryptonote::transaction& tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received);
+ void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
+ void process_outgoing(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received);
void add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount);
void generate_genesis(cryptonote::block& b);
void check_genesis(const crypto::hash& genesis_hash) const; //throws
@@ -610,7 +627,7 @@ namespace tools
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
uint64_t get_upper_tranaction_size_limit();
std::vector<uint64_t> get_unspent_amounts_vector();
- uint64_t get_fee_multiplier(uint32_t priority, bool use_new_fee) const;
+ uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm) const;
uint64_t get_dynamic_per_kb_fee_estimate();
uint64_t get_per_kb_fee();
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
@@ -620,6 +637,8 @@ namespace tools
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count);
bool wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki);
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
+ bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
+ std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
@@ -631,7 +650,7 @@ namespace tools
std::atomic<uint64_t> m_local_bc_height; //temporary workaround
std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
- std::unordered_map<crypto::hash, payment_details> m_unconfirmed_payments;
+ std::unordered_multimap<crypto::hash, payment_details> m_unconfirmed_payments;
std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
transfer_container m_transfers;
@@ -664,9 +683,10 @@ namespace tools
bool m_confirm_missing_payment_id;
bool m_ask_password;
NodeRPCProxy m_node_rpc_proxy;
+ std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 16)
+BOOST_CLASS_VERSION(tools::wallet2, 18)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index edead807f..eee1c8d3c 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -340,7 +340,7 @@ struct Wallet
* \param upper_transaction_size_limit
* \return - true on success
*/
- virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0;
+ virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit, const std::string &daemon_username = "", const std::string &daemon_password = "") = 0;
/*!
* \brief createWatchOnly - Creates a watch only wallet
@@ -696,13 +696,16 @@ struct WalletManager
virtual bool isMining() const = 0;
//! starts mining with the set number of threads
- virtual bool startMining(const std::string &address, uint32_t threads = 1) = 0;
+ virtual bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true) = 0;
//! stops mining
virtual bool stopMining() = 0;
//! resolves an OpenAlias address to a monero address
virtual std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const = 0;
+
+ //! checks for an update and returns version, hash and url
+ static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
};
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index 12799f613..1508f3791 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -73,6 +73,7 @@ namespace wallet_args
const char* const usage,
boost::program_options::options_description desc_params,
const boost::program_options::positional_options_description& positional_options,
+ const char *default_log_name,
bool log_to_console)
{
@@ -85,6 +86,7 @@ namespace wallet_args
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
const command_line::arg_descriptor<uint32_t> arg_max_concurrency = {"max-concurrency", wallet_args::tr("Max number of threads to use for a parallel job"), DEFAULT_MAX_CONCURRENCY};
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", wallet_args::tr("Specify log file"), ""};
+ const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", wallet_args::tr("Config file"), "", true};
std::string lang = i18n_get_language();
@@ -100,6 +102,7 @@ namespace wallet_args
command_line::add_arg(desc_params, arg_log_file, "");
command_line::add_arg(desc_params, arg_log_level);
command_line::add_arg(desc_params, arg_max_concurrency);
+ command_line::add_arg(desc_params, arg_config_file);
i18n_set_language("translations", "monero", lang);
@@ -108,43 +111,58 @@ namespace wallet_args
po::variables_map vm;
bool r = command_line::handle_error_helper(desc_all, [&]()
{
- po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm);
+ auto parser = po::command_line_parser(argc, argv).options(desc_all).positional(positional_options);
+ po::store(parser.run(), vm);
- if (command_line::get_arg(vm, command_line::arg_help))
- {
- tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
- tools::msg_writer() << wallet_args::tr("Usage:") << ' ' << usage;
- tools::msg_writer() << desc_all;
- return false;
- }
- else if (command_line::get_arg(vm, command_line::arg_version))
+ if(command_line::has_arg(vm, arg_config_file))
{
- tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
- return false;
+ std::string config = command_line::get_arg(vm, arg_config_file);
+ bf::path config_path(config);
+ boost::system::error_code ec;
+ if (bf::exists(config_path, ec))
+ {
+ po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), desc_params), vm);
+ }
+ else
+ {
+ tools::fail_msg_writer() << wallet_args::tr("Can't find config file ") << config;
+ return false;
+ }
}
- auto parser = po::command_line_parser(argc, argv).options(desc_params).positional(positional_options);
- po::store(parser.run(), vm);
po::notify(vm);
return true;
});
if (!r)
return boost::none;
- if(command_line::has_arg(vm, arg_max_concurrency))
- tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency));
-
std::string log_path;
if (!vm["log-file"].defaulted())
log_path = command_line::get_arg(vm, arg_log_file);
else
- log_path = mlog_get_default_log_path("monero-wallet-cli.log");
+ log_path = mlog_get_default_log_path(default_log_name);
mlog_configure(log_path, log_to_console);
if (!vm["log-level"].defaulted())
{
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
}
+ if (command_line::get_arg(vm, command_line::arg_help))
+ {
+ tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
+ tools::msg_writer() << wallet_args::tr("Usage:") << ' ' << usage;
+ tools::msg_writer() << desc_all;
+ return boost::none;
+ }
+ else if (command_line::get_arg(vm, command_line::arg_version))
+ {
+ tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
+ return boost::none;
+ }
+
+ if(command_line::has_arg(vm, arg_max_concurrency))
+ tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency));
+
tools::scoped_message_writer(epee::console_color_white, true) << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
if (!vm["log-level"].defaulted())
diff --git a/src/wallet/wallet_args.h b/src/wallet/wallet_args.h
index e0719d203..cf23ffded 100644
--- a/src/wallet/wallet_args.h
+++ b/src/wallet/wallet_args.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -50,5 +50,5 @@ namespace wallet_args
const char* const usage,
boost::program_options::options_description desc_params,
const boost::program_options::positional_options_description& positional_options,
- bool log_to_console = false);
+ const char *default_log_name, bool log_to_console = false);
}
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index fc0471be7..3e3578149 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index ee50c3cdb..f77ddf431 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -54,6 +54,7 @@ namespace
{
const command_line::arg_descriptor<std::string, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};
const command_line::arg_descriptor<bool> arg_disable_rpc_login = {"disable-rpc-login", "Disable HTTP authentication for RPC connections served by this process"};
+ const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", "Enable commands which rely on a trusted daemon", false};
constexpr const char default_rpc_username[] = "monero";
}
@@ -66,7 +67,7 @@ namespace tools
}
//------------------------------------------------------------------------------------------------------------------------------
- wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), rpc_login_filename(), m_stop(false)
+ wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), rpc_login_filename(), m_stop(false), m_trusted_daemon(false)
{}
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::~wallet_rpc_server()
@@ -112,6 +113,15 @@ namespace tools
boost::optional<epee::net_utils::http::login> http_login{};
std::string bind_port = command_line::get_arg(vm, arg_rpc_bind_port);
const bool disable_auth = command_line::get_arg(vm, arg_disable_rpc_login);
+ m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon);
+ if (!command_line::has_arg(vm, arg_trusted_daemon))
+ {
+ if (tools::is_local_address(m_wallet.get_daemon_address()))
+ {
+ MINFO(tr("Daemon is local, assuming trusted"));
+ m_trusted_daemon = true;
+ }
+ }
if (disable_auth)
{
@@ -242,7 +252,7 @@ namespace tools
res.balance = m_wallet.balance();
res.unlocked_balance = m_wallet.unlocked_balance();
}
- catch (std::exception& e)
+ catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -257,7 +267,7 @@ namespace tools
{
res.address = m_wallet.get_account().get_public_address_str(m_wallet.testnet());
}
- catch (std::exception& e)
+ catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -272,7 +282,7 @@ namespace tools
{
res.height = m_wallet.get_blockchain_current_height();
}
- catch (std::exception& e)
+ catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -290,7 +300,7 @@ namespace tools
cryptonote::tx_destination_entry de;
bool has_payment_id;
crypto::hash8 new_payment_id;
- if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet.testnet(), it->address))
+ if(!get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet.testnet(), it->address, false))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
@@ -381,7 +391,7 @@ namespace tools
LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2");
mixin = 2;
}
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
// reject proposed transactions if there are more than one. see on_transfer_split below.
if (ptx_vector.size() != 1)
@@ -451,7 +461,7 @@ namespace tools
}
std::vector<wallet2::pending_tx> ptx_vector;
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
- ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.trusted_daemon);
+ ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
LOG_PRINT_L2("on_transfer_split calling commit_txyy");
@@ -503,7 +513,7 @@ namespace tools
try
{
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_unmixable_sweep_transactions(req.trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_unmixable_sweep_transactions(m_trusted_daemon);
m_wallet.commit_tx(ptx_vector);
@@ -565,7 +575,7 @@ namespace tools
try
{
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.priority, extra, req.trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
m_wallet.commit_tx(ptx_vector);
@@ -626,7 +636,7 @@ namespace tools
res.payment_id = epee::string_tools::pod_to_hex(payment_id);
return true;
}
- catch (std::exception &e)
+ catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -659,7 +669,7 @@ namespace tools
res.payment_id = epee::string_tools::pod_to_hex(payment_id);
return true;
}
- catch (std::exception &e)
+ catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -681,7 +691,7 @@ namespace tools
{
m_wallet.store();
}
- catch (std::exception& e)
+ catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -901,7 +911,7 @@ namespace tools
{
m_wallet.rescan_blockchain();
}
- catch (std::exception& e)
+ catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -935,7 +945,7 @@ namespace tools
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet.testnet(), req.address))
+ if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet.testnet(), req.address, false))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "";
@@ -960,7 +970,7 @@ namespace tools
m_wallet.store();
m_stop.store(true, std::memory_order_relaxed);
}
- catch (std::exception& e)
+ catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
@@ -971,6 +981,13 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_set_tx_notes(const wallet_rpc::COMMAND_RPC_SET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_SET_TX_NOTES::response& res, epee::json_rpc::error& er)
{
+ if (m_wallet.restricted())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DENIED;
+ er.message = "Command unavailable in restricted mode.";
+ return false;
+ }
+
if (req.txids.size() != req.notes.size())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
@@ -1129,7 +1146,7 @@ namespace tools
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
m_wallet.get_payments(payments, 0);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
- if (i->first == txid)
+ if (i->second.m_tx_hash == txid)
{
fill_transfer_entry(res.transfer, i->second.m_tx_hash, i->first, i->second);
return true;
@@ -1198,6 +1215,13 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er)
{
+ if (m_wallet.restricted())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DENIED;
+ er.message = "Command unavailable in restricted mode.";
+ return false;
+ }
+
try
{
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
@@ -1294,11 +1318,18 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_add_address_book(const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er)
{
+ if (m_wallet.restricted())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DENIED;
+ er.message = "Command unavailable in restricted mode.";
+ return false;
+ }
+
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 payment_id8;
crypto::hash payment_id = cryptonote::null_hash;
- if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id8, m_wallet.testnet(), req.address))
+ if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet.testnet(), req.address, false))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
@@ -1348,6 +1379,13 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er)
{
+ if (m_wallet.restricted())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DENIED;
+ er.message = "Command unavailable in restricted mode.";
+ return false;
+ }
+
const auto ab = m_wallet.get_address_book();
if (req.index >= ab.size())
{
@@ -1364,6 +1402,28 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_rescan_spent(const wallet_rpc::COMMAND_RPC_RESCAN_SPENT::request& req, wallet_rpc::COMMAND_RPC_RESCAN_SPENT::response& res, epee::json_rpc::error& er)
+ {
+ if (m_wallet.restricted())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DENIED;
+ er.message = "Command unavailable in restricted mode.";
+ return false;
+ }
+ try
+ {
+ m_wallet.rescan_spent();
+ return true;
+ }
+ catch (const std::exception &e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = e.what();
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
}
int main(int argc, char** argv) {
@@ -1376,6 +1436,7 @@ int main(int argc, char** argv) {
tools::wallet2::init_options(desc_params);
command_line::add_arg(desc_params, arg_rpc_bind_port);
command_line::add_arg(desc_params, arg_disable_rpc_login);
+ command_line::add_arg(desc_params, arg_trusted_daemon);
cryptonote::rpc_args::init_options(desc_params);
command_line::add_arg(desc_params, arg_wallet_file);
command_line::add_arg(desc_params, arg_from_json);
@@ -1386,6 +1447,7 @@ int main(int argc, char** argv) {
"monero-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>] [--rpc-bind-port=<port>]",
desc_params,
po::positional_options_description(),
+ "monero-wallet-rpc.log",
true
);
if (!vm)
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 98e6e72ed..7dd07d12f 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -92,6 +92,7 @@ namespace tools
MAP_JON_RPC_WE("get_address_book", on_get_address_book, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY)
MAP_JON_RPC_WE("add_address_book", on_add_address_book, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY)
MAP_JON_RPC_WE("delete_address_book",on_delete_address_book,wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY)
+ MAP_JON_RPC_WE("rescan_spent", on_rescan_spent, wallet_rpc::COMMAND_RPC_RESCAN_SPENT)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -125,6 +126,7 @@ namespace tools
bool on_get_address_book(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er);
bool on_add_address_book(const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er);
bool on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er);
+ bool on_rescan_spent(const wallet_rpc::COMMAND_RPC_RESCAN_SPENT::request& req, wallet_rpc::COMMAND_RPC_RESCAN_SPENT::response& res, epee::json_rpc::error& er);
//json rpc v2
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er);
@@ -138,5 +140,6 @@ namespace tools
wallet2& m_wallet;
std::string rpc_login_filename;
std::atomic<bool> m_stop;
+ bool m_trusted_daemon;
};
}
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 86f37c658..2ec965b4d 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -119,7 +119,6 @@ namespace wallet_rpc
uint64_t unlock_time;
std::string payment_id;
bool get_tx_key;
- bool trusted_daemon;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(destinations)
@@ -128,7 +127,6 @@ namespace wallet_rpc
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(payment_id)
KV_SERIALIZE(get_tx_key)
- KV_SERIALIZE(trusted_daemon)
END_KV_SERIALIZE_MAP()
};
@@ -158,7 +156,6 @@ namespace wallet_rpc
uint64_t unlock_time;
std::string payment_id;
bool get_tx_keys;
- bool trusted_daemon;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(destinations)
@@ -167,7 +164,6 @@ namespace wallet_rpc
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(payment_id)
KV_SERIALIZE(get_tx_keys)
- KV_SERIALIZE(trusted_daemon)
END_KV_SERIALIZE_MAP()
};
@@ -199,11 +195,9 @@ namespace wallet_rpc
struct request
{
bool get_tx_keys;
- bool trusted_daemon;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(get_tx_keys)
- KV_SERIALIZE(trusted_daemon)
END_KV_SERIALIZE_MAP()
};
@@ -240,7 +234,6 @@ namespace wallet_rpc
uint64_t unlock_time;
std::string payment_id;
bool get_tx_keys;
- bool trusted_daemon;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
@@ -249,7 +242,6 @@ namespace wallet_rpc
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(payment_id)
KV_SERIALIZE(get_tx_keys)
- KV_SERIALIZE(trusted_daemon)
END_KV_SERIALIZE_MAP()
};
@@ -865,5 +857,20 @@ namespace wallet_rpc
};
};
+ struct COMMAND_RPC_RESCAN_SPENT
+ {
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
}
}
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 7b541c8f6..6f1c3bbbd 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//