|
|
@ -3,6 +3,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include "Wallet.h"
|
|
|
|
#include "Wallet.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
|
|
|
|
#include "PendingTransaction.h"
|
|
|
|
#include "PendingTransaction.h"
|
|
|
|
#include "UnsignedTransaction.h"
|
|
|
|
#include "UnsignedTransaction.h"
|
|
|
|
#include "TransactionHistory.h"
|
|
|
|
#include "TransactionHistory.h"
|
|
|
@ -28,6 +32,8 @@
|
|
|
|
#include <QVector>
|
|
|
|
#include <QVector>
|
|
|
|
#include <QMutexLocker>
|
|
|
|
#include <QMutexLocker>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "utils/ScopeGuard.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
namespace {
|
|
|
|
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
|
|
|
|
static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5;
|
|
|
|
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30;
|
|
|
|
static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 30;
|
|
|
@ -101,6 +107,20 @@ bool Wallet::disconnected() const
|
|
|
|
return m_disconnected;
|
|
|
|
return m_disconnected;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Wallet::refreshing() const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return m_refreshing;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Wallet::refreshingSet(bool value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (m_refreshing.exchange(value) != value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
emit refreshingChanged();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Wallet::setConnectionStatus(ConnectionStatus value)
|
|
|
|
void Wallet::setConnectionStatus(ConnectionStatus value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (m_connectionStatus == value)
|
|
|
|
if (m_connectionStatus == value)
|
|
|
@ -245,7 +265,7 @@ void Wallet::initAsync(
|
|
|
|
emit walletCreationHeightChanged();
|
|
|
|
emit walletCreationHeightChanged();
|
|
|
|
qDebug() << "init async finished - starting refresh";
|
|
|
|
qDebug() << "init async finished - starting refresh";
|
|
|
|
connected(true);
|
|
|
|
connected(true);
|
|
|
|
m_walletImpl->startRefresh();
|
|
|
|
startRefresh();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
if (future.first)
|
|
|
|
if (future.first)
|
|
|
@ -456,20 +476,14 @@ bool Wallet::importOutputs(const QString& path) {
|
|
|
|
return m_walletImpl->importOutputs(path.toStdString());
|
|
|
|
return m_walletImpl->importOutputs(path.toStdString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Wallet::refresh()
|
|
|
|
void Wallet::startRefresh()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
qDebug() << "refresh async";
|
|
|
|
m_refreshEnabled = true;
|
|
|
|
m_walletImpl->refreshAsync();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Wallet::startRefresh() const
|
|
|
|
void Wallet::pauseRefresh()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_walletImpl->startRefresh();
|
|
|
|
m_refreshEnabled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Wallet::pauseRefresh() const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_walletImpl->pauseRefresh();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
|
|
|
|
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
|
|
|
@ -580,6 +594,29 @@ bool Wallet::submitTxFile(const QString &fileName) const
|
|
|
|
return m_walletImpl->importKeyImages(fileName.toStdString() + "_keyImages");
|
|
|
|
return m_walletImpl->importKeyImages(fileName.toStdString() + "_keyImages");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Wallet::refresh(bool historyAndSubaddresses /* = true */)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
refreshingSet(true);
|
|
|
|
|
|
|
|
const auto cleanup = sg::make_scope_guard([this]() noexcept {
|
|
|
|
|
|
|
|
refreshingSet(false);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
QMutexLocker locker(&m_asyncMutex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool result = m_walletImpl->refresh();
|
|
|
|
|
|
|
|
if (historyAndSubaddresses)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_history->refresh(currentSubaddressAccount());
|
|
|
|
|
|
|
|
m_subaddress->refresh(currentSubaddressAccount());
|
|
|
|
|
|
|
|
m_subaddressAccount->getAll();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
|
|
|
|
emit updated();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Wallet::commitTransactionAsync(PendingTransaction *t)
|
|
|
|
void Wallet::commitTransactionAsync(PendingTransaction *t)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_scheduler.run([this, t] {
|
|
|
|
m_scheduler.run([this, t] {
|
|
|
@ -1063,6 +1100,8 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
|
|
|
, m_subaddressAccount(nullptr)
|
|
|
|
, m_subaddressAccount(nullptr)
|
|
|
|
, m_subaddressAccountModel(nullptr)
|
|
|
|
, m_subaddressAccountModel(nullptr)
|
|
|
|
, m_coinsModel(nullptr)
|
|
|
|
, m_coinsModel(nullptr)
|
|
|
|
|
|
|
|
, m_refreshEnabled(false)
|
|
|
|
|
|
|
|
, m_refreshing(false)
|
|
|
|
, m_scheduler(this)
|
|
|
|
, m_scheduler(this)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
|
|
|
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
|
|
@ -1081,12 +1120,17 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
|
|
|
m_connectionStatusRunning = false;
|
|
|
|
m_connectionStatusRunning = false;
|
|
|
|
m_daemonUsername = "";
|
|
|
|
m_daemonUsername = "";
|
|
|
|
m_daemonPassword = "";
|
|
|
|
m_daemonPassword = "";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
startRefreshThread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Wallet::~Wallet()
|
|
|
|
Wallet::~Wallet()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
qDebug("~Wallet: Closing wallet");
|
|
|
|
qDebug("~Wallet: Closing wallet");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pauseRefresh();
|
|
|
|
|
|
|
|
m_walletImpl->stop();
|
|
|
|
|
|
|
|
|
|
|
|
m_scheduler.shutdownWaitForFinished();
|
|
|
|
m_scheduler.shutdownWaitForFinished();
|
|
|
|
|
|
|
|
|
|
|
|
delete m_addressBook;
|
|
|
|
delete m_addressBook;
|
|
|
@ -1116,3 +1160,32 @@ Wallet::~Wallet()
|
|
|
|
m_walletListener = NULL;
|
|
|
|
m_walletListener = NULL;
|
|
|
|
qDebug("m_walletImpl deleted");
|
|
|
|
qDebug("m_walletImpl deleted");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Wallet::startRefreshThread()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto future = m_scheduler.run([this] {
|
|
|
|
|
|
|
|
constexpr const std::chrono::seconds refreshInterval{10};
|
|
|
|
|
|
|
|
constexpr const std::chrono::milliseconds intervalResolution{100};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto last = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
while (!m_scheduler.stopping())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (m_refreshEnabled)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto now = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
const auto elapsed = now - last;
|
|
|
|
|
|
|
|
if (elapsed >= refreshInterval)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
refresh(false);
|
|
|
|
|
|
|
|
last = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(intervalResolution);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!future.first)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
throw std::runtime_error("failed to start auto refresh thread");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|