Libwalletqt: integrate changes from upstream

Co-authored-by: xiphon <xiphon@protonmail.com>
This commit is contained in:
tobtoht 2020-10-14 16:49:13 +02:00
parent ffa8c3e5bf
commit 1ff8a2aaf4
4 changed files with 226 additions and 114 deletions

View file

@ -2,6 +2,11 @@
// Copyright (c) 2014-2020, The Monero Project. // Copyright (c) 2014-2020, The Monero Project.
#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"
@ -27,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;
@ -36,7 +43,7 @@ namespace {
} }
Wallet::Wallet(QObject * parent) Wallet::Wallet(QObject * parent)
: Wallet(nullptr, parent) : Wallet(nullptr, parent)
{ {
} }
@ -100,6 +107,19 @@ 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)
@ -111,7 +131,7 @@ void Wallet::setConnectionStatus(ConnectionStatus value)
emit connectionStatusChanged(m_connectionStatus); emit connectionStatusChanged(m_connectionStatus);
bool disconnected = m_connectionStatus == Wallet::ConnectionStatus_Connecting || bool disconnected = m_connectionStatus == Wallet::ConnectionStatus_Connecting ||
m_connectionStatus == Wallet::ConnectionStatus_Disconnected; m_connectionStatus == Wallet::ConnectionStatus_Disconnected;
if (m_disconnected != disconnected) if (m_disconnected != disconnected)
{ {
@ -120,6 +140,29 @@ void Wallet::setConnectionStatus(ConnectionStatus value)
} }
} }
QString Wallet::getProxyAddress() const
{
QMutexLocker locker(&m_proxyMutex);
return m_proxyAddress;
}
void Wallet::setProxyAddress(QString address)
{
m_scheduler.run([this, address] {
{
QMutexLocker locker(&m_proxyMutex);
if (!m_walletImpl->setProxy(address.toStdString()))
{
qCritical() << "failed to set proxy" << address;
}
m_proxyAddress = address;
}
emit proxyAddressChanged();
});
}
bool Wallet::synchronized() const bool Wallet::synchronized() const
{ {
return m_walletImpl->synchronized(); return m_walletImpl->synchronized();
@ -145,20 +188,18 @@ QString Wallet::path() const
return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->path())); return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->path()));
} }
//void Wallet::storeAsync(const QJSValue &callback, const QString &path /* = "" */)
//void Wallet::storeAsync(const QVariant &callback, const QString &path /* = "" */)
//{ //{
// const auto future = m_scheduler.run( // const auto future = m_scheduler.run(
// [this, path] { // [this, path] {
// QMutexLocker locker(&m_storeMutex); // QMutexLocker locker(&m_asyncMutex);
//
// return QVariantList({m_walletImpl->store(path.toStdString())}); // return QJSValueList({m_walletImpl->store(path.toStdString())});
// }, // },
// callback); // callback);
// if (!future.first) // if (!future.first)
// { // {
// QVariant(callback).call(QVariantList({false})); // QJSValue(callback).call(QJSValueList({false}));
// } // }
//} //}
@ -167,7 +208,7 @@ void Wallet::store(const QString &path)
m_walletImpl->store(path.toStdString()); m_walletImpl->store(path.toStdString());
} }
bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight) bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight, const QString& proxyAddress)
{ {
qDebug() << "init non async"; qDebug() << "init non async";
if (isRecovering){ if (isRecovering){
@ -181,7 +222,20 @@ bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 uppe
if (isRecovering || isRecoveringFromDevice) { if (isRecovering || isRecoveringFromDevice) {
m_walletImpl->setRefreshFromBlockHeight(restoreHeight); m_walletImpl->setRefreshFromBlockHeight(restoreHeight);
} }
m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString());
{
QMutexLocker locker(&m_proxyMutex);
if (!m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), false, false, proxyAddress.toStdString()))
{
return false;
}
m_proxyAddress = proxyAddress;
}
emit proxyAddressChanged();
setTrustedDaemon(trustedDaemon); setTrustedDaemon(trustedDaemon);
return true; return true;
} }
@ -193,17 +247,24 @@ void Wallet::setDaemonLogin(const QString &daemonUsername, const QString &daemon
m_daemonPassword = daemonPassword; m_daemonPassword = daemonPassword;
} }
void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight) void Wallet::initAsync(
const QString &daemonAddress,
bool trustedDaemon /* = false */,
quint64 upperTransactionLimit /* = 0 */,
bool isRecovering /* = false */,
bool isRecoveringFromDevice /* = false */,
quint64 restoreHeight /* = 0 */,
const QString &proxyAddress /* = "" */)
{ {
qDebug() << "initAsync: " + daemonAddress; qDebug() << "initAsync: " + daemonAddress;
const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight] { const auto future = m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress] {
bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight); bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight, proxyAddress);
if (success) if (success)
{ {
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)
@ -372,7 +433,7 @@ quint64 Wallet::daemonBlockChainHeight() const
// cache daemon blockchain height for some time (60 seconds by default) // cache daemon blockchain height for some time (60 seconds by default)
if (m_daemonBlockChainHeight == 0 if (m_daemonBlockChainHeight == 0
|| m_daemonBlockChainHeightTime.elapsed() / 1000 > m_daemonBlockChainHeightTtl) { || m_daemonBlockChainHeightTime.elapsed() / 1000 > m_daemonBlockChainHeightTtl) {
m_daemonBlockChainHeight = m_walletImpl->daemonBlockChainHeight(); m_daemonBlockChainHeight = m_walletImpl->daemonBlockChainHeight();
m_daemonBlockChainHeightTime.restart(); m_daemonBlockChainHeightTime.restart();
} }
@ -382,7 +443,7 @@ quint64 Wallet::daemonBlockChainHeight() const
quint64 Wallet::daemonBlockChainTargetHeight() const quint64 Wallet::daemonBlockChainTargetHeight() const
{ {
if (m_daemonBlockChainTargetHeight <= 1 if (m_daemonBlockChainTargetHeight <= 1
|| m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) { || m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) {
m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight(); m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight();
// Target height is set to 0 if daemon is synced. // Target height is set to 0 if daemon is synced.
@ -406,42 +467,37 @@ bool Wallet::importKeyImages(const QString& path)
return m_walletImpl->importKeyImages(path.toStdString()); return m_walletImpl->importKeyImages(path.toStdString());
} }
bool Wallet::refresh() bool Wallet::refresh(bool historyAndSubaddresses /* = true */)
{ {
bool result = m_walletImpl->refresh(); refreshingSet(true);
m_history->refresh(currentSubaddressAccount()); const auto cleanup = sg::make_scope_guard([this]() noexcept {
m_subaddress->refresh(currentSubaddressAccount()); refreshingSet(false);
m_coins->refresh(currentSubaddressAccount()); });
m_subaddressAccount->getAll();
if (result) {
emit updated(); QMutexLocker locker(&m_asyncMutex);
return result;
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::refreshAsync() void Wallet::startRefresh()
{ {
qDebug() << "refresh async"; m_refreshEnabled = true;
m_walletImpl->refreshAsync();
} }
void Wallet::setAutoRefreshInterval(int seconds) void Wallet::pauseRefresh()
{ {
m_walletImpl->setAutoRefreshInterval(seconds); m_refreshEnabled = false;
}
int Wallet::autoRefreshInterval() const
{
return m_walletImpl->autoRefreshInterval();
}
void Wallet::startRefresh() const
{
m_walletImpl->startRefresh();
}
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,
@ -450,15 +506,15 @@ PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QSt
{ {
std::set<uint32_t> subaddr_indices; std::set<uint32_t> subaddr_indices;
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction( Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count, dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices); static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
PendingTransaction * result = new PendingTransaction(ptImpl,0); PendingTransaction * result = new PendingTransaction(ptImpl,0);
return result; return result;
} }
void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id, void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id,
quint64 amount, quint32 mixin_count, quint64 amount, quint32 mixin_count,
PendingTransaction::Priority priority) PendingTransaction::Priority priority)
{ {
m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] { m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] {
PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority); PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority);
@ -471,15 +527,15 @@ PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const
{ {
std::set<uint32_t> subaddr_indices; std::set<uint32_t> subaddr_indices;
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction( Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
dst_addr.toStdString(), payment_id.toStdString(), Monero::optional<uint64_t>(), mixin_count, dst_addr.toStdString(), payment_id.toStdString(), Monero::optional<uint64_t>(), mixin_count,
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices); static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
PendingTransaction * result = new PendingTransaction(ptImpl, this); PendingTransaction * result = new PendingTransaction(ptImpl, this);
return result; return result;
} }
void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id, void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
quint32 mixin_count, quint32 mixin_count,
PendingTransaction::Priority priority) PendingTransaction::Priority priority)
{ {
m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] { m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] {
PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority); PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority);
@ -556,7 +612,6 @@ void Wallet::disposeTransaction(UnsignedTransaction *t)
delete t; delete t;
} }
// @ TODO: QJSValue could probably be QVARIANT
//void Wallet::estimateTransactionFeeAsync(const QString &destination, //void Wallet::estimateTransactionFeeAsync(const QString &destination,
// quint64 amount, // quint64 amount,
// PendingTransaction::Priority priority, // PendingTransaction::Priority priority,
@ -564,8 +619,8 @@ void Wallet::disposeTransaction(UnsignedTransaction *t)
//{ //{
// m_scheduler.run([this, destination, amount, priority] { // m_scheduler.run([this, destination, amount, priority] {
// const uint64_t fee = m_walletImpl->estimateTransactionFee( // const uint64_t fee = m_walletImpl->estimateTransactionFee(
// {std::make_pair(destination.toStdString(), amount)}, // {std::make_pair(destination.toStdString(), amount)},
// static_cast<Monero::PendingTransaction::Priority>(priority)); // static_cast<Monero::PendingTransaction::Priority>(priority));
// return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))}); // return QJSValueList({QString::fromStdString(Monero::Wallet::displayAmount(fee))});
// }, callback); // }, callback);
//} //}
@ -683,17 +738,17 @@ bool Wallet::setCacheAttribute(const QString &key, const QString &val)
bool Wallet::setUserNote(const QString &txid, const QString &note) bool Wallet::setUserNote(const QString &txid, const QString &note)
{ {
return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString()); return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString());
} }
QString Wallet::getUserNote(const QString &txid) const QString Wallet::getUserNote(const QString &txid) const
{ {
return QString::fromStdString(m_walletImpl->getUserNote(txid.toStdString())); return QString::fromStdString(m_walletImpl->getUserNote(txid.toStdString()));
} }
QString Wallet::getTxKey(const QString &txid) const QString Wallet::getTxKey(const QString &txid) const
{ {
return QString::fromStdString(m_walletImpl->getTxKey(txid.toStdString())); return QString::fromStdString(m_walletImpl->getTxKey(txid.toStdString()));
} }
//void Wallet::getTxKeyAsync(const QString &txid, const QJSValue &callback) //void Wallet::getTxKeyAsync(const QString &txid, const QJSValue &callback)
@ -831,7 +886,6 @@ bool Wallet::verifySignedMessage(const QString &message, const QString &address,
return m_walletImpl->verifySignedMessage(message.toStdString(), address.toStdString(), signature.toStdString()); return m_walletImpl->verifySignedMessage(message.toStdString(), address.toStdString(), signature.toStdString());
} }
} }
bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error)
{ {
std::string s_address, s_payment_id, s_tx_description, s_recipient_name, s_error; std::string s_address, s_payment_id, s_tx_description, s_recipient_name, s_error;
@ -852,6 +906,8 @@ bool Wallet::parse_uri(const QString &uri, QString &address, QString &payment_id
bool Wallet::rescanSpent() bool Wallet::rescanSpent()
{ {
QMutexLocker locker(&m_asyncMutex);
return m_walletImpl->rescanSpent(); return m_walletImpl->rescanSpent();
} }
@ -928,8 +984,8 @@ QString Wallet::getRing(const QString &key_image)
{ {
if (!ring.isEmpty()) if (!ring.isEmpty())
ring = ring + " "; ring = ring + " ";
QString s; QString s;
s.setNum(out); s.setNum(out);
ring = ring + s; ring = ring + s;
} }
return ring; return ring;
@ -949,8 +1005,8 @@ QString Wallet::getRings(const QString &txid)
for (uint64_t out: cring.second) for (uint64_t out: cring.second)
{ {
ring = ring + " "; ring = ring + " ";
QString s; QString s;
s.setNum(out); s.setNum(out);
ring = ring + s; ring = ring + s;
} }
} }
@ -964,9 +1020,9 @@ bool Wallet::setRing(const QString &key_image, const QString &ring, bool relativ
foreach(QString str, strOuts) foreach(QString str, strOuts)
{ {
uint64_t out; uint64_t out;
bool ok; bool ok;
out = str.toULong(&ok); out = str.toULong(&ok);
if (ok) if (ok)
cring.push_back(out); cring.push_back(out);
} }
return m_walletImpl->setRing(key_image.toStdString(), cring, relative); return m_walletImpl->setRing(key_image.toStdString(), cring, relative);
@ -1001,26 +1057,28 @@ void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device
} }
Wallet::Wallet(Monero::Wallet *w, QObject *parent) Wallet::Wallet(Monero::Wallet *w, QObject *parent)
: QObject(parent) : QObject(parent)
, m_walletImpl(w) , m_walletImpl(w)
, m_history(nullptr) , m_history(nullptr)
, m_historyModel(nullptr) , m_historyModel(nullptr)
, m_addressBook(nullptr) , m_addressBook(nullptr)
, m_addressBookModel(nullptr) , m_addressBookModel(nullptr)
, m_daemonBlockChainHeight(0) , m_daemonBlockChainHeight(0)
, m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS) , m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS)
, m_daemonBlockChainTargetHeight(0) , m_daemonBlockChainTargetHeight(0)
, m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS) , m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS)
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected) , m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
, m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS) , m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS)
, m_disconnected(true) , m_disconnected(true)
, m_currentSubaddressAccount(0) , m_currentSubaddressAccount(0)
, m_subaddress(nullptr) , m_subaddress(nullptr)
, m_subaddressModel(nullptr) , m_subaddressModel(nullptr)
, m_subaddressAccount(nullptr) , m_subaddressAccount(nullptr)
, m_subaddressAccountModel(nullptr) , m_subaddressAccountModel(nullptr)
, m_coinsModel(nullptr) , m_coinsModel(nullptr)
, m_scheduler(this) , m_refreshEnabled(false)
, m_refreshing(false)
, m_scheduler(this)
{ {
m_history = new TransactionHistory(m_walletImpl->history(), this); m_history = new TransactionHistory(m_walletImpl->history(), this);
m_addressBook = new AddressBook(m_walletImpl->addressBook(), this); m_addressBook = new AddressBook(m_walletImpl->addressBook(), this);
@ -1038,11 +1096,13 @@ 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");
m_scheduler.shutdownWaitForFinished(); m_scheduler.shutdownWaitForFinished();
@ -1072,3 +1132,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] {
static constexpr const size_t refreshIntervalSec = 10;
static constexpr const size_t intervalResolutionMs = 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 = std::chrono::duration_cast<std::chrono::seconds>(now - last).count();
if (elapsed >= refreshIntervalSec)
{
refresh(false);
last = std::chrono::steady_clock::now();
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(intervalResolutionMs));
}
});
if (!future.first)
{
throw std::runtime_error("failed to start auto refresh thread");
}
}

View file

@ -8,7 +8,6 @@
#include <QObject> #include <QObject>
#include <QMutex> #include <QMutex>
#include <QList> #include <QList>
//#include <QJSValue>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include "wallet/api/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here; #include "wallet/api/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here;
@ -20,14 +19,13 @@
#include "WalletListenerImpl.h" #include "WalletListenerImpl.h"
namespace Monero { namespace Monero {
struct Wallet; // forward declaration struct Wallet; // forward declaration
} }
class TransactionHistory; class TransactionHistory;
class TransactionHistoryModel; class TransactionHistoryModel;
class TransactionHistoryProxyModel; class TransactionHistoryProxyModel;
class TransactionHistorySortFilterModel;
class AddressBook; class AddressBook;
class AddressBookModel; class AddressBookModel;
class Subaddress; class Subaddress;
@ -50,13 +48,14 @@ struct TxProofResult {
class Wallet : public QObject, public PassprasePrompter class Wallet : public QObject, public PassprasePrompter
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged) Q_PROPERTY(bool disconnected READ disconnected NOTIFY disconnectedChanged)
Q_PROPERTY(bool refreshing READ refreshing NOTIFY refreshingChanged)
Q_PROPERTY(QString seed READ getSeed) Q_PROPERTY(QString seed READ getSeed)
Q_PROPERTY(QString seedLanguage READ getSeedLanguage) Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
Q_PROPERTY(Status status READ status) Q_PROPERTY(Status status READ status)
Q_PROPERTY(NetworkType::Type nettype READ nettype) Q_PROPERTY(NetworkType::Type nettype READ nettype)
Q_PROPERTY(ConnectionStatus connected READ connected) // Q_PROPERTY(ConnectionStatus connected READ connected)
Q_PROPERTY(quint32 currentSubaddressAccount READ currentSubaddressAccount NOTIFY currentSubaddressAccountChanged) Q_PROPERTY(quint32 currentSubaddressAccount READ currentSubaddressAccount NOTIFY currentSubaddressAccountChanged)
Q_PROPERTY(bool synchronized READ synchronized) Q_PROPERTY(bool synchronized READ synchronized)
Q_PROPERTY(QString errorString READ errorString) Q_PROPERTY(QString errorString READ errorString)
@ -76,6 +75,7 @@ class Wallet : public QObject, public PassprasePrompter
Q_PROPERTY(QString secretSpendKey READ getSecretSpendKey) Q_PROPERTY(QString secretSpendKey READ getSecretSpendKey)
Q_PROPERTY(QString publicSpendKey READ getPublicSpendKey) Q_PROPERTY(QString publicSpendKey READ getPublicSpendKey)
Q_PROPERTY(QString daemonLogPath READ getDaemonLogPath CONSTANT) Q_PROPERTY(QString daemonLogPath READ getDaemonLogPath CONSTANT)
Q_PROPERTY(QString proxyAddress READ getProxyAddress WRITE setProxyAddress NOTIFY proxyAddressChanged)
Q_PROPERTY(quint64 walletCreationHeight READ getWalletCreationHeight WRITE setWalletCreationHeight NOTIFY walletCreationHeightChanged) Q_PROPERTY(quint64 walletCreationHeight READ getWalletCreationHeight WRITE setWalletCreationHeight NOTIFY walletCreationHeightChanged)
public: public:
@ -120,6 +120,7 @@ public:
//! returns true if wallet was ever synchronized //! returns true if wallet was ever synchronized
bool synchronized() const; bool synchronized() const;
//! returns last operation's error message //! returns last operation's error message
QString errorString() const; QString errorString() const;
@ -138,7 +139,14 @@ public:
// Q_INVOKABLE void storeAsync(const QJSValue &callback, const QString &path = ""); // Q_INVOKABLE void storeAsync(const QJSValue &callback, const QString &path = "");
//! initializes wallet asynchronously //! initializes wallet asynchronously
Q_INVOKABLE void initAsync(const QString &daemonAddress, bool trustedDaemon = false, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0); Q_INVOKABLE void initAsync(
const QString &daemonAddress,
bool trustedDaemon = false,
quint64 upperTransactionLimit = 0,
bool isRecovering = false,
bool isRecoveringFromDevice = false,
quint64 restoreHeight = 0,
const QString &proxyAddress = "");
// Set daemon rpc user/pass // Set daemon rpc user/pass
Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = ""); Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
@ -188,20 +196,11 @@ public:
Q_INVOKABLE bool importKeyImages(const QString& path); Q_INVOKABLE bool importKeyImages(const QString& path);
//! refreshes the wallet //! refreshes the wallet
Q_INVOKABLE bool refresh(); Q_INVOKABLE bool refresh(bool historyAndSubaddresses = true);
//! refreshes the wallet asynchronously
Q_INVOKABLE void refreshAsync();
//! setup auto-refresh interval in seconds
Q_INVOKABLE void setAutoRefreshInterval(int seconds);
//! return auto-refresh interval in seconds
Q_INVOKABLE int autoRefreshInterval() const;
// pause/resume refresh // pause/resume refresh
Q_INVOKABLE void startRefresh() const; Q_INVOKABLE void startRefresh();
Q_INVOKABLE void pauseRefresh() const; Q_INVOKABLE void pauseRefresh();
//! returns current wallet's block height //! returns current wallet's block height
//! (can be less than daemon's blockchain height when wallet sync in progress) //! (can be less than daemon's blockchain height when wallet sync in progress)
@ -225,7 +224,7 @@ public:
//! creates transaction with all outputs //! creates transaction with all outputs
Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id, Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
quint32 mixin_count, PendingTransaction::Priority priority); quint32 mixin_count, PendingTransaction::Priority priority);
//! creates async transaction with all outputs //! creates async transaction with all outputs
Q_INVOKABLE void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id, Q_INVOKABLE void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
@ -402,6 +401,8 @@ signals:
void connectionStatusChanged(int status) const; void connectionStatusChanged(int status) const;
void currentSubaddressAccountChanged() const; void currentSubaddressAccountChanged() const;
void disconnectedChanged() const; void disconnectedChanged() const;
void proxyAddressChanged() const;
void refreshingChanged() const;
private: private:
Wallet(QObject * parent = nullptr); Wallet(QObject * parent = nullptr);
@ -409,10 +410,22 @@ private:
~Wallet(); ~Wallet();
//! initializes wallet //! initializes wallet
bool init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight); bool init(
const QString &daemonAddress,
bool trustedDaemon,
quint64 upperTransactionLimit,
bool isRecovering,
bool isRecoveringFromDevice,
quint64 restoreHeight,
const QString& proxyAddress);
bool disconnected() const; bool disconnected() const;
bool refreshing() const;
void refreshingSet(bool value);
void setConnectionStatus(ConnectionStatus value); void setConnectionStatus(ConnectionStatus value);
QString getProxyAddress() const;
void setProxyAddress(QString address);
void startRefreshThread();
private: private:
friend class WalletManager; friend class WalletManager;
@ -445,13 +458,17 @@ private:
mutable SubaddressAccountModel * m_subaddressAccountModel; mutable SubaddressAccountModel * m_subaddressAccountModel;
Coins * m_coins; Coins * m_coins;
mutable CoinsModel * m_coinsModel; mutable CoinsModel * m_coinsModel;
QMutex m_asyncMutex;
QMutex m_connectionStatusMutex; QMutex m_connectionStatusMutex;
bool m_connectionStatusRunning; bool m_connectionStatusRunning;
QString m_daemonUsername; QString m_daemonUsername;
QString m_daemonPassword; QString m_daemonPassword;
QString m_proxyAddress;
mutable QMutex m_proxyMutex;
std::atomic<bool> m_refreshEnabled;
std::atomic<bool> m_refreshing;
WalletListenerImpl *m_walletListener; WalletListenerImpl *m_walletListener;
FutureScheduler m_scheduler; FutureScheduler m_scheduler;
QMutex m_storeMutex;
}; };

View file

@ -68,6 +68,11 @@ QPair<bool, QFuture<void>> FutureScheduler::run(std::function<void()> function)
// }); // });
//} //}
bool FutureScheduler::stopping() const noexcept
{
return Stopping;
}
bool FutureScheduler::add() noexcept bool FutureScheduler::add() noexcept
{ {
QMutexLocker locker(&Mutex); QMutexLocker locker(&Mutex);

View file

@ -26,6 +26,7 @@ public:
QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept; QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept;
// QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList()> function, const QJSValue &callback); // QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList()> function, const QJSValue &callback);
bool stopping() const noexcept;
private: private:
bool add() noexcept; bool add() noexcept;
@ -62,7 +63,7 @@ private:
size_t Alive; size_t Alive;
QWaitCondition Condition; QWaitCondition Condition;
QMutex Mutex; QMutex Mutex;
bool Stopping; std::atomic<bool> Stopping;
}; };
#endif // FUTURE_SCHEDULER_H #endif // FUTURE_SCHEDULER_H