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.h1
-rw-r--r--src/wallet/api/wallet_manager.cpp4
-rw-r--r--src/wallet/api/wallet_manager.h1
-rw-r--r--src/wallet/node_rpc_proxy.cpp37
-rw-r--r--src/wallet/node_rpc_proxy.h25
-rw-r--r--src/wallet/wallet2.cpp66
-rw-r--r--src/wallet/wallet2.h18
-rw-r--r--src/wallet/wallet2_api.h14
-rw-r--r--src/wallet/wallet_rpc_server.cpp4
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h2
11 files changed, 154 insertions, 24 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index a2bb44cfe..c0974f880 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -35,6 +35,7 @@
#include "transaction_history.h"
#include "address_book.h"
#include "common_defines.h"
+#include "common/util.h"
#include "mnemonics/electrum-words.h"
#include <boost/format.hpp>
@@ -1411,6 +1412,11 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st
return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
}
+std::string WalletImpl::getDefaultDataDir() const
+{
+ return tools::get_default_data_dir();
+}
+
bool WalletImpl::rescanSpent()
{
clearStatus();
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 07b0f063b..8190c7873 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -129,6 +129,7 @@ public:
virtual void startRefresh();
virtual void pauseRefresh();
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
+ virtual std::string getDefaultDataDir() const;
private:
void clearStatus() const;
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index b2f947972..a23533530 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -125,6 +125,10 @@ bool WalletManagerImpl::walletExists(const std::string &path)
return false;
}
+bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const
+{
+ return tools::wallet2::verify_password(keys_file_name, password, watch_only);
+}
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)
{
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 033e8108f..aa6ea439e 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -50,6 +50,7 @@ public:
const std::string &spendKeyString = "");
virtual bool closeWallet(Wallet *wallet);
bool walletExists(const std::string &path);
+ bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const;
std::vector<std::string> findWallets(const std::string &path);
std::string errorString() const;
void setDaemonAddress(const std::string &address);
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index 1143a89d7..9f30e4ac5 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -48,6 +48,8 @@ NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_clien
, m_dynamic_per_kb_fee_estimate_cached_height(0)
, m_dynamic_per_kb_fee_estimate_grace_blocks(0)
, m_rpc_version(0)
+ , m_target_height(0)
+ , m_target_height_time(0)
{}
void NodeRPCProxy::invalidate()
@@ -60,9 +62,11 @@ void NodeRPCProxy::invalidate()
m_dynamic_per_kb_fee_estimate_cached_height = 0;
m_dynamic_per_kb_fee_estimate_grace_blocks = 0;
m_rpc_version = 0;
+ m_target_height = 0;
+ m_target_height_time = 0;
}
-boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version)
+boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
{
const time_t now = time(NULL);
if (m_rpc_version == 0)
@@ -84,7 +88,7 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height)
+boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const
{
const time_t now = time(NULL);
if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
@@ -110,7 +114,32 @@ void NodeRPCProxy::set_height(uint64_t h)
m_height = h;
}
-boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height)
+boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const
+{
+ const time_t now = time(NULL);
+ if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
+ {
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_INFO::request> req_t = AUTO_VAL_INIT(req_t);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_INFO::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_info";
+ 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 target blockchain height");
+ m_target_height = resp_t.result.target_height;
+ m_target_height_time = now;
+ }
+ height = m_target_height;
+ return boost::optional<std::string>();
+}
+
+boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
{
if (m_earliest_height[version] == 0)
{
@@ -134,7 +163,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version,
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee)
+boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
{
uint64_t height;
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 02d1d8d93..fb288189a 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -43,23 +43,26 @@ public:
void invalidate();
- boost::optional<std::string> get_rpc_version(uint32_t &version);
- boost::optional<std::string> get_height(uint64_t &height);
+ boost::optional<std::string> get_rpc_version(uint32_t &version) const;
+ boost::optional<std::string> get_height(uint64_t &height) const;
void set_height(uint64_t h);
- boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height);
- boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee);
+ boost::optional<std::string> get_target_height(uint64_t &height) const;
+ boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const;
+ boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const;
private:
epee::net_utils::http::http_simple_client &m_http_client;
boost::mutex &m_daemon_rpc_mutex;
- uint64_t m_height;
- time_t m_height_time;
- uint64_t m_earliest_height[256];
- 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;
+ mutable uint64_t m_height;
+ mutable time_t m_height_time;
+ mutable uint64_t m_earliest_height[256];
+ mutable uint64_t m_dynamic_per_kb_fee_estimate;
+ mutable uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
+ mutable uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
+ mutable uint32_t m_rpc_version;
+ mutable uint64_t m_target_height;
+ mutable time_t m_target_height_time;
};
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index e569197b8..b63e07b2d 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1097,6 +1097,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
}
entry.first->second.m_block_height = height;
entry.first->second.m_timestamp = ts;
+ entry.first->second.m_unlock_time = tx.unlock_time;
}
//----------------------------------------------------------------------------------------------------
void wallet2::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)
@@ -1878,6 +1879,10 @@ bool wallet2::clear()
m_payments.clear();
m_tx_keys.clear();
m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
+ m_scanned_pool_txs[0].clear();
+ m_scanned_pool_txs[1].clear();
+ m_address_book.clear();
m_local_bc_height = 1;
return true;
}
@@ -1958,6 +1963,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p
value2.SetInt(m_merge_destinations ? 1 :0);
json.AddMember("merge_destinations", value2, json.GetAllocator());
+ value2.SetInt(m_testnet ? 1 :0);
+ json.AddMember("testnet", value2, json.GetAllocator());
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -2099,6 +2107,11 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
m_min_output_value = field_min_output_value;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, merge_destinations, int, Int, false, false);
m_merge_destinations = field_merge_destinations;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet);
+ // Wallet is being opened with testnet flag, but is saved as a mainnet wallet
+ THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet");
+ // Wallet is being opened without testnet flag but is saved as a testnet wallet.
+ THROW_WALLET_EXCEPTION_IF(!m_testnet && field_testnet, error::wallet_internal_error, "Testnet wallet can not be opened as mainnet wallet");
}
const cryptonote::account_keys& keys = m_account.get_keys();
@@ -2113,6 +2126,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
/*!
* \brief verify password for default wallet keys file.
* \param password Password to verify
+ * \return true if password is correct
*
* for verification only
* should not mutate state, unlike load_keys()
@@ -2121,7 +2135,23 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
*/
bool wallet2::verify_password(const std::string& password) const
{
- const std::string keys_file_name = m_keys_file;
+ return verify_password(m_keys_file, password, m_watch_only);
+}
+
+/*!
+ * \brief verify password for specified wallet keys file.
+ * \param keys_file_name Keys file to verify password for
+ * \param password Password to verify
+ * \param watch_only If set = only verify view keys, otherwise also spend keys
+ * \return true if password is correct
+ *
+ * for verification only
+ * should not mutate state, unlike load_keys()
+ * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password
+ *
+ */
+bool wallet2::verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only)
+{
wallet2::keys_file_data keys_file_data;
std::string buf;
bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
@@ -2154,7 +2184,7 @@ bool wallet2::verify_password(const std::string& password) const
const cryptonote::account_keys& keys = account_data_check.get_keys();
r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
- if(!m_watch_only)
+ if(!watch_only)
r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
return r;
}
@@ -2192,9 +2222,26 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri
// try asking the daemon first
if(m_refresh_from_block_height == 0 && !recover){
std::string err;
- uint64_t height = get_daemon_blockchain_height(err);
- if (err.empty())
- m_refresh_from_block_height = height - blocks_per_month;
+ uint64_t height = 0;
+
+ // we get the max of approximated height and known height
+ // approximated height is the least of daemon target height
+ // (the max of what the other daemons are claiming is their
+ // height) and the theoretical height based on the local
+ // clock. This will be wrong only if both the local clock
+ // is bad *and* a peer daemon claims a highest height than
+ // the real chain.
+ // known height is the height the local daemon is currently
+ // synced to, it will be lower than the real chain height if
+ // the daemon is currently syncing.
+ height = get_approximate_blockchain_height();
+ uint64_t target_height = get_daemon_blockchain_target_height(err);
+ if (err.empty() && target_height < height)
+ height = target_height;
+ uint64_t local_height = get_daemon_blockchain_height(err);
+ if (err.empty() && local_height > height)
+ height = local_height;
+ m_refresh_from_block_height = height >= blocks_per_month ? height - blocks_per_month : 0;
}
if(m_refresh_from_block_height == 0 && !recover){
@@ -5685,6 +5732,15 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
}
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::is_synced() const
+{
+ uint64_t height;
+ boost::optional<std::string> result = m_node_rpc_proxy.get_target_height(height);
+ if (result && *result != CORE_RPC_STATUS_OK)
+ return false;
+ return get_blockchain_current_height() >= height;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index b853c5f3c..ba9abacf5 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -129,6 +129,8 @@ namespace tools
//! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm);
+ static bool verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only);
+
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
struct transfer_details
@@ -199,10 +201,11 @@ namespace tools
std::vector<cryptonote::tx_destination_entry> m_dests;
crypto::hash m_payment_id;
uint64_t m_timestamp;
+ uint64_t m_unlock_time;
- confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash) {}
+ confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash), m_timestamp(0), m_unlock_time(0) {}
confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height):
- m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp) {}
+ m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time) {}
};
struct tx_construction_data
@@ -597,6 +600,8 @@ namespace tools
uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31
+ bool is_synced() const;
+
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -704,7 +709,7 @@ 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)
-BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
+BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 4)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 16)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
@@ -879,6 +884,13 @@ namespace boost
x.m_amount_out += x.m_change;
}
}
+ if (ver < 4)
+ {
+ if (!typename Archive::is_saving())
+ x.m_unlock_time = 0;
+ return;
+ }
+ a & x.m_unlock_time;
}
template <class Archive>
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index ce431ee6b..8da8c62eb 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -596,6 +596,9 @@ struct Wallet
virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
+
+ virtual std::string getDefaultDataDir() const = 0;
+
/*
* \brief rescanSpent - Rescan spent outputs - Can only be used with trusted daemon
* \return true on success
@@ -669,11 +672,20 @@ struct WalletManager
/*!
* @brief TODO: delme walletExists - check if the given filename is the wallet
* @param path - filename
- * @return
+ * @return - true if wallet exists
*/
virtual bool walletExists(const std::string &path) = 0;
/*!
+ * @brief verifyWalletPassword - check if the given filename is the wallet
+ * @param keys_file_name - location of keys file
+ * @param password - password to verify
+ * @param watch_only - verify only view keys?
+ * @return - true if password is correct
+ */
+ virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const = 0;
+
+ /*!
* \brief findWallets - searches for the wallet files by given path name recursively
* \param path - starting point to search
* \return - list of strings with found wallets (absolute paths);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 133f93f92..77911e9a7 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -236,6 +236,7 @@ namespace tools
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "in";
@@ -249,6 +250,7 @@ namespace tools
entry.payment_id = entry.payment_id.substr(0,16);
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = pd.m_amount_in - pd.m_amount_out;
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
entry.amount = pd.m_amount_in - change - entry.fee;
@@ -276,6 +278,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.fee = pd.m_amount_in - pd.m_amount_out;
entry.amount = pd.m_amount_in - pd.m_change - entry.fee;
+ entry.unlock_time = pd.m_tx.unlock_time;
entry.note = m_wallet->get_tx_note(txid);
entry.type = is_failed ? "failed" : "pending";
}
@@ -289,6 +292,7 @@ namespace tools
entry.height = 0;
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "pool";
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 5832bb032..fa5c154de 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -560,6 +560,7 @@ namespace wallet_rpc
std::string note;
std::list<transfer_destination> destinations;
std::string type;
+ uint64_t unlock_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txid);
@@ -571,6 +572,7 @@ namespace wallet_rpc
KV_SERIALIZE(note);
KV_SERIALIZE(destinations);
KV_SERIALIZE(type);
+ KV_SERIALIZE(unlock_time)
END_KV_SERIALIZE_MAP()
};