mirror of
https://git.wownero.com/wowlet/wowlet.git
synced 2024-08-15 01:03:14 +00:00
Libwalletqt: integrate changes from upstream
Co-authored-by: xiphon <xiphon@protonmail.com>
This commit is contained in:
parent
ffa8c3e5bf
commit
1ff8a2aaf4
4 changed files with 226 additions and 114 deletions
|
@ -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 ¬e)
|
bool Wallet::setUserNote(const QString &txid, const QString ¬e)
|
||||||
{
|
{
|
||||||
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue