Wallet API: Do not refresh while daemon is syncing

+ fixed fast refresh when creating wallet offline
+ improved close wallet logic (make sure refresh thread is stopped)
This commit is contained in:
Jaquee 2016-12-14 12:18:52 +01:00
parent b97a2f72db
commit 944b6079d9
No known key found for this signature in database
GPG key ID: 384E52B09F45DC39
3 changed files with 65 additions and 22 deletions

View file

@ -204,6 +204,7 @@ WalletImpl::WalletImpl(bool testnet)
, m_recoveringFromSeed(false) , m_recoveringFromSeed(false)
, m_synchronized(false) , m_synchronized(false)
, m_rebuildWalletCache(false) , m_rebuildWalletCache(false)
, m_is_connected(false)
{ {
m_wallet = new tools::wallet2(testnet); m_wallet = new tools::wallet2(testnet);
m_history = new TransactionHistoryImpl(this); m_history = new TransactionHistoryImpl(this);
@ -224,11 +225,19 @@ WalletImpl::WalletImpl(bool testnet)
WalletImpl::~WalletImpl() WalletImpl::~WalletImpl()
{ {
LOG_PRINT_L1(__FUNCTION__);
// Pause refresh thread - prevents refresh from starting again
pauseRefresh();
// Close wallet - stores cache and stops ongoing refresh operation
close();
// Stop refresh thread
stopRefresh(); stopRefresh();
delete m_wallet2Callback;
delete m_history; delete m_history;
delete m_addressBook; delete m_addressBook;
delete m_wallet; delete m_wallet;
delete m_wallet2Callback; LOG_PRINT_L1(__FUNCTION__ << " finished");
} }
bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language) bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
@ -329,7 +338,7 @@ bool WalletImpl::close()
{ {
bool result = false; bool result = false;
LOG_PRINT_L3("closing wallet..."); LOG_PRINT_L1("closing wallet...");
try { try {
// Do not store wallet with invalid status // Do not store wallet with invalid status
// Status Critical refers to errors on opening or creating wallets. // Status Critical refers to errors on opening or creating wallets.
@ -337,10 +346,10 @@ bool WalletImpl::close()
m_wallet->store(); m_wallet->store();
else else
LOG_PRINT_L3("Status_Critical - not storing wallet"); LOG_PRINT_L3("Status_Critical - not storing wallet");
LOG_PRINT_L3("wallet::store done"); LOG_PRINT_L1("wallet::store done");
LOG_PRINT_L3("Calling wallet::stop..."); LOG_PRINT_L1("Calling wallet::stop...");
m_wallet->stop(); m_wallet->stop();
LOG_PRINT_L3("wallet::stop done"); LOG_PRINT_L1("wallet::stop done");
result = true; result = true;
clearStatus(); clearStatus();
} catch (const std::exception &e) { } catch (const std::exception &e) {
@ -487,6 +496,8 @@ uint64_t WalletImpl::approximateBlockChainHeight() const
} }
uint64_t WalletImpl::daemonBlockChainHeight() const uint64_t WalletImpl::daemonBlockChainHeight() const
{ {
if (!m_is_connected)
return 0;
std::string err; std::string err;
uint64_t result = m_wallet->get_daemon_blockchain_height(err); uint64_t result = m_wallet->get_daemon_blockchain_height(err);
if (!err.empty()) { if (!err.empty()) {
@ -504,6 +515,8 @@ uint64_t WalletImpl::daemonBlockChainHeight() const
uint64_t WalletImpl::daemonBlockChainTargetHeight() const uint64_t WalletImpl::daemonBlockChainTargetHeight() const
{ {
if (!m_is_connected)
return 0;
std::string err; std::string err;
uint64_t result = m_wallet->get_daemon_blockchain_target_height(err); uint64_t result = m_wallet->get_daemon_blockchain_target_height(err);
if (!err.empty()) { if (!err.empty()) {
@ -516,9 +529,20 @@ uint64_t WalletImpl::daemonBlockChainTargetHeight() const
m_status = Status_Ok; m_status = Status_Ok;
m_errorString = ""; m_errorString = "";
} }
// Target height can be 0 when daemon is synced. Use blockchain height instead.
if(result == 0)
result = daemonBlockChainHeight();
return result; return result;
} }
bool WalletImpl::daemonSynced() const
{
if(connected() == Wallet::ConnectionStatus_Disconnected)
return false;
uint64_t blockChainHeight = daemonBlockChainHeight();
return (blockChainHeight >= daemonBlockChainTargetHeight() && blockChainHeight > 1);
}
bool WalletImpl::synchronized() const bool WalletImpl::synchronized() const
{ {
return m_synchronized; return m_synchronized;
@ -924,8 +948,8 @@ bool WalletImpl::connectToDaemon()
Wallet::ConnectionStatus WalletImpl::connected() const Wallet::ConnectionStatus WalletImpl::connected() const
{ {
uint32_t version = 0; uint32_t version = 0;
bool is_connected = m_wallet->check_connection(&version); m_is_connected = m_wallet->check_connection(&version);
if (!is_connected) if (!m_is_connected)
return Wallet::ConnectionStatus_Disconnected; return Wallet::ConnectionStatus_Disconnected;
if ((version >> 16) != CORE_RPC_VERSION_MAJOR) if ((version >> 16) != CORE_RPC_VERSION_MAJOR)
return Wallet::ConnectionStatus_WrongVersion; return Wallet::ConnectionStatus_WrongVersion;
@ -970,7 +994,7 @@ void WalletImpl::refreshThreadFunc()
LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired..."); LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired...");
LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled); LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled);
LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << m_status); LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << m_status);
if (m_refreshEnabled /*&& m_status == Status_Ok*/) { if (m_refreshEnabled) {
LOG_PRINT_L3(__FUNCTION__ << ": refreshing..."); LOG_PRINT_L3(__FUNCTION__ << ": refreshing...");
doRefresh(); doRefresh();
} }
@ -983,15 +1007,22 @@ void WalletImpl::doRefresh()
// synchronizing async and sync refresh calls // synchronizing async and sync refresh calls
boost::lock_guard<boost::mutex> guarg(m_refreshMutex2); boost::lock_guard<boost::mutex> guarg(m_refreshMutex2);
try { try {
m_wallet->refresh(); // Syncing daemon and refreshing wallet simultaneously is very resource intensive.
if (!m_synchronized) { // Disable refresh if wallet is disconnected or daemon isn't synced.
m_synchronized = true; if (daemonSynced()) {
} // Use fast refresh for new wallets
// assuming if we have empty history, it wasn't initialized yet if (isNewWallet())
// for futher history changes client need to update history in m_wallet->set_refresh_from_block_height(daemonBlockChainHeight());
// "on_money_received" and "on_money_sent" callbacks m_wallet->refresh();
if (m_history->count() == 0) { if (!m_synchronized) {
m_history->refresh(); m_synchronized = true;
}
// assuming if we have empty history, it wasn't initialized yet
// for futher history changes client need to update history in
// "on_money_received" and "on_money_sent" callbacks
if (m_history->count() == 0) {
m_history->refresh();
}
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
m_status = Status_Error; m_status = Status_Error;

View file

@ -107,14 +107,15 @@ public:
virtual std::string getTxKey(const std::string &txid) const; virtual std::string getTxKey(const std::string &txid) const;
virtual std::string signMessage(const std::string &message); virtual std::string signMessage(const std::string &message);
virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const; virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const;
virtual void startRefresh();
virtual void pauseRefresh();
private: private:
void clearStatus(); void clearStatus();
void refreshThreadFunc(); void refreshThreadFunc();
void doRefresh(); void doRefresh();
void startRefresh(); bool daemonSynced() const;
void stopRefresh(); void stopRefresh();
void pauseRefresh();
bool isNewWallet() const; bool isNewWallet() const;
void doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit); void doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
@ -148,9 +149,11 @@ private:
// flag indicating wallet is recovering from seed // flag indicating wallet is recovering from seed
// so it shouldn't be considered as new and pull blocks (slow-refresh) // so it shouldn't be considered as new and pull blocks (slow-refresh)
// instead of pulling hashes (fast-refresh) // instead of pulling hashes (fast-refresh)
bool m_recoveringFromSeed; std::atomic<bool> m_recoveringFromSeed;
std::atomic<bool> m_synchronized; std::atomic<bool> m_synchronized;
bool m_rebuildWalletCache; std::atomic<bool> m_rebuildWalletCache;
// cache connection status to avoid unnecessary RPC calls
mutable std::atomic<bool> m_is_connected;
}; };

View file

@ -364,6 +364,15 @@ struct Wallet
static std::string paymentIdFromAddress(const std::string &str, bool testnet); static std::string paymentIdFromAddress(const std::string &str, bool testnet);
static uint64_t maximumAllowedAmount(); static uint64_t maximumAllowedAmount();
/**
* @brief StartRefresh - Start/resume refresh thread (refresh every 10 seconds)
*/
virtual void startRefresh() = 0;
/**
* @brief pauseRefresh - pause refresh thread
*/
virtual void pauseRefresh() = 0;
/** /**
* @brief refresh - refreshes the wallet, updating transactions from daemon * @brief refresh - refreshes the wallet, updating transactions from daemon
* @return - true if refreshed successfully; * @return - true if refreshed successfully;