2015-05-27 12:08:46 +00:00
|
|
|
// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers
|
2014-08-13 10:38:35 +00:00
|
|
|
//
|
|
|
|
// This file is part of Bytecoin.
|
|
|
|
//
|
|
|
|
// Bytecoin is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Bytecoin is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "WalletLegacy.h"
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
2015-07-09 14:52:47 +00:00
|
|
|
#include <time.h>
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "WalletLegacy/WalletHelper.h"
|
|
|
|
#include "WalletLegacy/WalletLegacySerialization.h"
|
|
|
|
#include "WalletLegacy/WalletLegacySerializer.h"
|
|
|
|
#include "WalletLegacy/WalletUtils.h"
|
|
|
|
|
|
|
|
using namespace Crypto;
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
const uint64_t ACCOUN_CREATE_TIME_ACCURACY = 24 * 60 * 60;
|
|
|
|
|
2014-06-25 17:21:42 +00:00
|
|
|
void throwNotDefined() {
|
|
|
|
throw std::runtime_error("The behavior is not defined!");
|
|
|
|
}
|
|
|
|
|
|
|
|
class ContextCounterHolder
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ContextCounterHolder(CryptoNote::WalletAsyncContextCounter& shutdowner) : m_shutdowner(shutdowner) {}
|
|
|
|
~ContextCounterHolder() { m_shutdowner.delAsyncContext(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
CryptoNote::WalletAsyncContextCounter& m_shutdowner;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename F>
|
|
|
|
void runAtomic(std::mutex& mutex, F f) {
|
|
|
|
std::unique_lock<std::mutex> lock(mutex);
|
|
|
|
f();
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
class InitWaiter : public CryptoNote::IWalletLegacyObserver {
|
2015-04-06 16:13:07 +00:00
|
|
|
public:
|
|
|
|
InitWaiter() : future(promise.get_future()) {}
|
|
|
|
|
|
|
|
virtual void initCompleted(std::error_code result) override {
|
|
|
|
promise.set_value(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code waitInit() {
|
|
|
|
return future.get();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::promise<std::error_code> promise;
|
|
|
|
std::future<std::error_code> future;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
class SaveWaiter : public CryptoNote::IWalletLegacyObserver {
|
2015-04-06 16:13:07 +00:00
|
|
|
public:
|
|
|
|
SaveWaiter() : future(promise.get_future()) {}
|
|
|
|
|
|
|
|
virtual void saveCompleted(std::error_code result) override {
|
|
|
|
promise.set_value(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code waitSave() {
|
|
|
|
return future.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::promise<std::error_code> promise;
|
|
|
|
std::future<std::error_code> future;
|
|
|
|
};
|
2015-07-09 14:52:47 +00:00
|
|
|
|
2014-06-25 17:21:42 +00:00
|
|
|
} //namespace
|
|
|
|
|
|
|
|
namespace CryptoNote {
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
class SyncStarter : public CryptoNote::IWalletLegacyObserver {
|
2015-04-06 16:13:07 +00:00
|
|
|
public:
|
|
|
|
SyncStarter(BlockchainSynchronizer& sync) : m_sync(sync) {}
|
|
|
|
virtual ~SyncStarter() {}
|
2014-08-13 10:51:37 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
virtual void initCompleted(std::error_code result) {
|
|
|
|
if (!result) {
|
|
|
|
m_sync.start();
|
|
|
|
}
|
2014-08-13 10:51:37 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
BlockchainSynchronizer& m_sync;
|
|
|
|
};
|
2014-08-13 10:51:37 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
WalletLegacy::WalletLegacy(const CryptoNote::Currency& currency, INode& node) :
|
2015-04-06 16:13:07 +00:00
|
|
|
m_state(NOT_INITIALIZED),
|
|
|
|
m_currency(currency),
|
|
|
|
m_node(node),
|
|
|
|
m_isStopping(false),
|
2015-05-27 12:08:46 +00:00
|
|
|
m_lastNotifiedActualBalance(0),
|
|
|
|
m_lastNotifiedPendingBalance(0),
|
2015-04-06 16:13:07 +00:00
|
|
|
m_blockchainSync(node, currency.genesisBlockHash()),
|
|
|
|
m_transfersSync(currency, m_blockchainSync, node),
|
|
|
|
m_transferDetails(nullptr),
|
|
|
|
m_sender(nullptr),
|
|
|
|
m_onInitSyncStarter(new SyncStarter(m_blockchainSync))
|
|
|
|
{
|
|
|
|
addObserver(m_onInitSyncStarter.get());
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
WalletLegacy::~WalletLegacy() {
|
2015-04-06 16:13:07 +00:00
|
|
|
removeObserver(m_onInitSyncStarter.get());
|
|
|
|
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
if (m_state != NOT_INITIALIZED) {
|
|
|
|
m_sender->stop();
|
|
|
|
m_isStopping = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-09 14:52:47 +00:00
|
|
|
m_blockchainSync.removeObserver(this);
|
|
|
|
m_blockchainSync.stop();
|
|
|
|
m_asyncContextCounter.waitAsyncContextsFinish();
|
|
|
|
m_sender.release();
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::addObserver(IWalletLegacyObserver* observer) {
|
2014-06-25 17:21:42 +00:00
|
|
|
m_observerManager.add(observer);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::removeObserver(IWalletLegacyObserver* observer) {
|
2014-06-25 17:21:42 +00:00
|
|
|
m_observerManager.remove(observer);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::initAndGenerate(const std::string& password) {
|
2014-06-25 17:21:42 +00:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> stateLock(m_cacheMutex);
|
|
|
|
|
|
|
|
if (m_state != NOT_INITIALIZED) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw std::system_error(make_error_code(error::ALREADY_INITIALIZED));
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_account.generate();
|
|
|
|
m_password = password;
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
initSync();
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::initCompleted, std::error_code());
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::initWithKeys(const AccountKeys& accountKeys, const std::string& password) {
|
2015-04-06 16:13:07 +00:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> stateLock(m_cacheMutex);
|
|
|
|
|
|
|
|
if (m_state != NOT_INITIALIZED) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw std::system_error(make_error_code(error::ALREADY_INITIALIZED));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
m_account.setAccountKeys(accountKeys);
|
2015-05-27 12:08:46 +00:00
|
|
|
m_account.set_createtime(ACCOUN_CREATE_TIME_ACCURACY);
|
2015-04-06 16:13:07 +00:00
|
|
|
m_password = password;
|
|
|
|
|
|
|
|
initSync();
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::initCompleted, std::error_code());
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::initAndLoad(std::istream& source, const std::string& password) {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> stateLock(m_cacheMutex);
|
|
|
|
|
|
|
|
if (m_state != NOT_INITIALIZED) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw std::system_error(make_error_code(error::ALREADY_INITIALIZED));
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_password = password;
|
|
|
|
m_state = LOADING;
|
2015-07-09 14:52:47 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
m_asyncContextCounter.addAsyncContext();
|
2015-07-30 15:22:07 +00:00
|
|
|
std::thread loader(&WalletLegacy::doLoad, this, std::ref(source));
|
2014-06-25 17:21:42 +00:00
|
|
|
loader.detach();
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::initSync() {
|
2015-04-06 16:13:07 +00:00
|
|
|
AccountSubscription sub;
|
2015-07-30 15:22:07 +00:00
|
|
|
sub.keys = reinterpret_cast<const AccountKeys&>(m_account.getAccountKeys());
|
2015-04-08 15:08:54 +00:00
|
|
|
sub.transactionSpendableAge = 1;
|
2015-04-06 16:13:07 +00:00
|
|
|
sub.syncStart.height = 0;
|
2015-05-27 12:08:46 +00:00
|
|
|
sub.syncStart.timestamp = m_account.get_createtime() - ACCOUN_CREATE_TIME_ACCURACY;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
auto& subObject = m_transfersSync.addSubscription(sub);
|
|
|
|
m_transferDetails = &subObject.getContainer();
|
|
|
|
subObject.addObserver(this);
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
m_sender.reset(new WalletTransactionSender(m_currency, m_transactionsCache, m_account.getAccountKeys(), *m_transferDetails));
|
2015-04-06 16:13:07 +00:00
|
|
|
m_state = INITIALIZED;
|
2015-07-09 14:52:47 +00:00
|
|
|
|
|
|
|
m_blockchainSync.addObserver(this);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::doLoad(std::istream& source) {
|
2015-04-06 16:13:07 +00:00
|
|
|
ContextCounterHolder counterHolder(m_asyncContextCounter);
|
|
|
|
try {
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
|
|
|
|
std::string cache;
|
2015-07-30 15:22:07 +00:00
|
|
|
WalletLegacySerializer serializer(m_account, m_transactionsCache);
|
2015-04-06 16:13:07 +00:00
|
|
|
serializer.deserialize(source, m_password, cache);
|
|
|
|
|
|
|
|
initSync();
|
|
|
|
|
|
|
|
try {
|
2015-07-09 14:52:47 +00:00
|
|
|
if (!cache.empty()) {
|
|
|
|
std::stringstream stream(cache);
|
|
|
|
m_transfersSync.load(stream);
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
} catch (const std::exception&) {
|
|
|
|
// ignore cache loading errors
|
2015-07-09 14:52:47 +00:00
|
|
|
}
|
|
|
|
} catch (std::system_error& e) {
|
2015-07-30 15:22:07 +00:00
|
|
|
runAtomic(m_cacheMutex, [this] () {this->m_state = WalletLegacy::NOT_INITIALIZED;} );
|
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::initCompleted, e.code());
|
2014-06-25 17:21:42 +00:00
|
|
|
return;
|
2015-07-09 14:52:47 +00:00
|
|
|
} catch (std::exception&) {
|
2015-07-30 15:22:07 +00:00
|
|
|
runAtomic(m_cacheMutex, [this] () {this->m_state = WalletLegacy::NOT_INITIALIZED;} );
|
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::initCompleted, make_error_code(CryptoNote::error::INTERNAL_WALLET_ERROR));
|
2014-06-25 17:21:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::initCompleted, std::error_code());
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::shutdown() {
|
2014-06-25 17:21:42 +00:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
|
|
|
|
if (m_isStopping)
|
|
|
|
throwNotDefined();
|
|
|
|
|
|
|
|
m_isStopping = true;
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
if (m_state != INITIALIZED)
|
2014-06-25 17:21:42 +00:00
|
|
|
throwNotDefined();
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
m_sender->stop();
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
m_blockchainSync.removeObserver(this);
|
|
|
|
m_blockchainSync.stop();
|
2014-06-25 17:21:42 +00:00
|
|
|
m_asyncContextCounter.waitAsyncContextsFinish();
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
m_sender.release();
|
|
|
|
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
m_isStopping = false;
|
|
|
|
m_state = NOT_INITIALIZED;
|
2015-07-09 14:52:47 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
const auto& accountAddress = m_account.getAccountKeys().address;
|
2015-07-09 14:52:47 +00:00
|
|
|
auto subObject = m_transfersSync.getSubscription(accountAddress);
|
|
|
|
assert(subObject != nullptr);
|
|
|
|
subObject->removeObserver(this);
|
|
|
|
m_transfersSync.removeSubscription(accountAddress);
|
|
|
|
m_transferDetails = nullptr;
|
|
|
|
|
|
|
|
m_transactionsCache.reset();
|
|
|
|
m_lastNotifiedActualBalance = 0;
|
|
|
|
m_lastNotifiedPendingBalance = 0;
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::reset() {
|
2015-04-06 16:13:07 +00:00
|
|
|
try {
|
2015-07-30 15:22:07 +00:00
|
|
|
std::error_code saveError;
|
|
|
|
std::stringstream ss;
|
|
|
|
{
|
|
|
|
SaveWaiter saveWaiter;
|
|
|
|
WalletHelper::IWalletRemoveObserverGuard saveGuarantee(*this, saveWaiter);
|
|
|
|
save(ss, false, false);
|
|
|
|
saveError = saveWaiter.waitSave();
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-09 14:52:47 +00:00
|
|
|
if (!saveError) {
|
|
|
|
shutdown();
|
2015-07-30 15:22:07 +00:00
|
|
|
InitWaiter initWaiter;
|
|
|
|
WalletHelper::IWalletRemoveObserverGuard initGuarantee(*this, initWaiter);
|
2015-07-09 14:52:47 +00:00
|
|
|
initAndLoad(ss, m_password);
|
2015-04-06 16:13:07 +00:00
|
|
|
initWaiter.waitInit();
|
2015-07-09 14:52:47 +00:00
|
|
|
}
|
|
|
|
} catch (std::exception& e) {
|
|
|
|
std::cout << "exception in reset: " << e.what() << std::endl;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::save(std::ostream& destination, bool saveDetailed, bool saveCache) {
|
2014-06-25 17:21:42 +00:00
|
|
|
if(m_isStopping) {
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::saveCompleted, make_error_code(CryptoNote::error::OPERATION_CANCELLED));
|
2014-06-25 17:21:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
throwIf(m_state != INITIALIZED, CryptoNote::error::WRONG_STATE);
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
m_state = SAVING;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_asyncContextCounter.addAsyncContext();
|
2015-07-30 15:22:07 +00:00
|
|
|
std::thread saver(&WalletLegacy::doSave, this, std::ref(destination), saveDetailed, saveCache);
|
2014-06-25 17:21:42 +00:00
|
|
|
saver.detach();
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::doSave(std::ostream& destination, bool saveDetailed, bool saveCache) {
|
2014-06-25 17:21:42 +00:00
|
|
|
ContextCounterHolder counterHolder(m_asyncContextCounter);
|
|
|
|
|
|
|
|
try {
|
2015-04-06 16:13:07 +00:00
|
|
|
m_blockchainSync.stop();
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
WalletLegacySerializer serializer(m_account, m_transactionsCache);
|
2015-04-06 16:13:07 +00:00
|
|
|
std::string cache;
|
|
|
|
|
|
|
|
if (saveCache) {
|
|
|
|
std::stringstream stream;
|
|
|
|
m_transfersSync.save(stream);
|
|
|
|
cache = stream.str();
|
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
serializer.serialize(destination, m_password, saveDetailed, cache);
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
m_state = INITIALIZED;
|
2015-04-06 16:13:07 +00:00
|
|
|
m_blockchainSync.start(); //XXX: start can throw. what to do in this case?
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
catch (std::system_error& e) {
|
2015-07-30 15:22:07 +00:00
|
|
|
runAtomic(m_cacheMutex, [this] () {this->m_state = WalletLegacy::INITIALIZED;} );
|
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::saveCompleted, e.code());
|
2014-06-25 17:21:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
catch (std::exception&) {
|
2015-07-30 15:22:07 +00:00
|
|
|
runAtomic(m_cacheMutex, [this] () {this->m_state = WalletLegacy::INITIALIZED;} );
|
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::saveCompleted, make_error_code(CryptoNote::error::INTERNAL_WALLET_ERROR));
|
2014-06-25 17:21:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::saveCompleted, std::error_code());
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::error_code WalletLegacy::changePassword(const std::string& oldPassword, const std::string& newPassword) {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> passLock(m_cacheMutex);
|
|
|
|
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
|
|
|
if (m_password.compare(oldPassword))
|
2015-05-27 12:08:46 +00:00
|
|
|
return make_error_code(CryptoNote::error::WRONG_PASSWORD);
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
//we don't let the user to change the password while saving
|
|
|
|
m_password = newPassword;
|
|
|
|
|
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::string WalletLegacy::getAddress() {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
2014-08-13 10:51:37 +00:00
|
|
|
return m_currency.accountAddressAsString(m_account);
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
uint64_t WalletLegacy::actualBalance() {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
return m_transferDetails->balance(ITransfersContainer::IncludeKeyUnlocked) -
|
|
|
|
m_transactionsCache.unconfrimedOutsAmount();
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
uint64_t WalletLegacy::pendingBalance() {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
uint64_t change = m_transactionsCache.unconfrimedOutsAmount() - m_transactionsCache.unconfirmedTransactionsAmount();
|
|
|
|
return m_transferDetails->balance(ITransfersContainer::IncludeKeyNotUnlocked) + change;
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t WalletLegacy::getTransactionCount() {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
|
|
|
return m_transactionsCache.getTransactionCount();
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t WalletLegacy::getTransferCount() {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
|
|
|
return m_transactionsCache.getTransferCount();
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TransactionId WalletLegacy::findTransactionByTransferId(TransferId transferId) {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
|
|
|
return m_transactionsCache.findTransactionByTransferId(transferId);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
bool WalletLegacy::getTransaction(TransactionId transactionId, WalletLegacyTransaction& transaction) {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
|
|
|
return m_transactionsCache.getTransaction(transactionId, transaction);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
bool WalletLegacy::getTransfer(TransferId transferId, WalletLegacyTransfer& transfer) {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
throwIfNotInitialised();
|
|
|
|
|
|
|
|
return m_transactionsCache.getTransfer(transferId, transfer);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TransactionId WalletLegacy::sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
|
|
|
|
std::vector<WalletLegacyTransfer> transfers;
|
2014-06-25 17:21:42 +00:00
|
|
|
transfers.push_back(transfer);
|
2015-04-06 16:13:07 +00:00
|
|
|
throwIfNotInitialised();
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
return sendTransaction(transfers, fee, extra, mixIn, unlockTimestamp);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TransactionId WalletLegacy::sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
|
2014-06-25 17:21:42 +00:00
|
|
|
TransactionId txId = 0;
|
|
|
|
std::shared_ptr<WalletRequest> request;
|
2015-07-30 15:22:07 +00:00
|
|
|
std::deque<std::shared_ptr<WalletLegacyEvent>> events;
|
2015-04-06 16:13:07 +00:00
|
|
|
throwIfNotInitialised();
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
2015-04-06 16:13:07 +00:00
|
|
|
request = m_sender->makeSendRequest(txId, events, transfers, fee, extra, mixIn, unlockTimestamp);
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
notifyClients(events);
|
|
|
|
|
|
|
|
if (request) {
|
|
|
|
m_asyncContextCounter.addAsyncContext();
|
2015-07-30 15:22:07 +00:00
|
|
|
request->perform(m_node, std::bind(&WalletLegacy::sendTransactionCallback, this, std::placeholders::_1, std::placeholders::_2));
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return txId;
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::sendTransactionCallback(WalletRequest::Callback callback, std::error_code ec) {
|
2014-06-25 17:21:42 +00:00
|
|
|
ContextCounterHolder counterHolder(m_asyncContextCounter);
|
2015-07-30 15:22:07 +00:00
|
|
|
std::deque<std::shared_ptr<WalletLegacyEvent> > events;
|
2014-06-25 17:21:42 +00:00
|
|
|
|
|
|
|
boost::optional<std::shared_ptr<WalletRequest> > nextRequest;
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
callback(events, nextRequest, ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
notifyClients(events);
|
|
|
|
|
|
|
|
if (nextRequest) {
|
|
|
|
m_asyncContextCounter.addAsyncContext();
|
2015-07-30 15:22:07 +00:00
|
|
|
(*nextRequest)->perform(m_node, std::bind(&WalletLegacy::synchronizationCallback, this, std::placeholders::_1, std::placeholders::_2));
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::synchronizationCallback(WalletRequest::Callback callback, std::error_code ec) {
|
2014-06-25 17:21:42 +00:00
|
|
|
ContextCounterHolder counterHolder(m_asyncContextCounter);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::deque<std::shared_ptr<WalletLegacyEvent> > events;
|
2014-06-25 17:21:42 +00:00
|
|
|
boost::optional<std::shared_ptr<WalletRequest> > nextRequest;
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
|
|
|
callback(events, nextRequest, ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
notifyClients(events);
|
|
|
|
|
|
|
|
if (nextRequest) {
|
|
|
|
m_asyncContextCounter.addAsyncContext();
|
2015-07-30 15:22:07 +00:00
|
|
|
(*nextRequest)->perform(m_node, std::bind(&WalletLegacy::synchronizationCallback, this, std::placeholders::_1, std::placeholders::_2));
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::error_code WalletLegacy::cancelTransaction(size_t transactionId) {
|
2015-05-27 12:08:46 +00:00
|
|
|
return make_error_code(CryptoNote::error::TX_CANCEL_IMPOSSIBLE);
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::synchronizationProgressUpdated(uint32_t current, uint32_t total) {
|
2015-04-06 16:13:07 +00:00
|
|
|
// forward notification
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::synchronizationProgressUpdated, current, total);
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
// check if balance has changed and notify client
|
|
|
|
notifyIfBalanceChanged();
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::synchronizationCompleted(std::error_code result) {
|
2015-04-06 16:13:07 +00:00
|
|
|
if (result != std::make_error_code(std::errc::interrupted)) {
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::synchronizationCompleted, result);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
notifyIfBalanceChanged();
|
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::onTransactionUpdated(ITransfersSubscription* object, const Hash& transactionHash) {
|
|
|
|
std::shared_ptr<WalletLegacyEvent> event;
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
TransactionInformation txInfo;
|
|
|
|
int64_t txBalance;
|
|
|
|
if (m_transferDetails->getTransactionInformation(transactionHash, txInfo, txBalance)) {
|
2014-06-25 17:21:42 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
2015-04-06 16:13:07 +00:00
|
|
|
event = m_transactionsCache.onTransactionUpdated(txInfo, txBalance);
|
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
if (event.get()) {
|
|
|
|
event->notify(m_observerManager);
|
|
|
|
}
|
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::onTransactionDeleted(ITransfersSubscription* object, const Hash& transactionHash) {
|
|
|
|
std::shared_ptr<WalletLegacyEvent> event;
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
{
|
2015-05-27 12:08:46 +00:00
|
|
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
2015-04-06 16:13:07 +00:00
|
|
|
event = m_transactionsCache.onTransactionDeleted(transactionHash);
|
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
if (event.get()) {
|
|
|
|
event->notify(m_observerManager);
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
2014-06-25 17:21:42 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::throwIfNotInitialised() {
|
2015-05-27 12:08:46 +00:00
|
|
|
if (m_state == NOT_INITIALIZED || m_state == LOADING) {
|
|
|
|
throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED));
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
assert(m_transferDetails);
|
2014-06-25 17:21:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::notifyClients(std::deque<std::shared_ptr<WalletLegacyEvent> >& events) {
|
2014-06-25 17:21:42 +00:00
|
|
|
while (!events.empty()) {
|
2015-07-30 15:22:07 +00:00
|
|
|
std::shared_ptr<WalletLegacyEvent> event = events.front();
|
2014-06-25 17:21:42 +00:00
|
|
|
event->notify(m_observerManager);
|
|
|
|
events.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::notifyIfBalanceChanged() {
|
2015-04-06 16:13:07 +00:00
|
|
|
auto actual = actualBalance();
|
|
|
|
auto prevActual = m_lastNotifiedActualBalance.exchange(actual);
|
|
|
|
|
|
|
|
if (prevActual != actual) {
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::actualBalanceUpdated, actual);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto pending = pendingBalance();
|
|
|
|
auto prevPending = m_lastNotifiedPendingBalance.exchange(pending);
|
|
|
|
|
|
|
|
if (prevPending != pending) {
|
2015-07-30 15:22:07 +00:00
|
|
|
m_observerManager.notify(&IWalletLegacyObserver::pendingBalanceUpdated, pending);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void WalletLegacy::getAccountKeys(AccountKeys& keys) {
|
2015-04-06 16:13:07 +00:00
|
|
|
if (m_state == NOT_INITIALIZED) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
keys = m_account.getAccountKeys();
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 17:21:42 +00:00
|
|
|
} //namespace CryptoNote
|