Simplewallet improvements
This commit is contained in:
parent
ad291f5285
commit
6d45be9ec0
|
@ -35,7 +35,10 @@ namespace {
|
||||||
|
|
||||||
void handleSignal() {
|
void handleSignal() {
|
||||||
static std::mutex m_mutex;
|
static std::mutex m_mutex;
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
std::unique_lock<std::mutex> lock(m_mutex, std::try_to_lock);
|
||||||
|
if (!lock.owns_lock()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_handler();
|
m_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +78,7 @@ namespace tools {
|
||||||
#else
|
#else
|
||||||
signal(SIGINT, posixHandler);
|
signal(SIGINT, posixHandler);
|
||||||
signal(SIGTERM, posixHandler);
|
signal(SIGTERM, posixHandler);
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
m_handler = t;
|
m_handler = t;
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -237,10 +237,6 @@ std::pair<Ipv4Address, uint16_t> TcpConnection::getPeerAddressAndPort() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpConnection::TcpConnection(Dispatcher& dispatcher, int socket) : dispatcher(&dispatcher), connection(socket), stopped(false), readContext(nullptr), writeContext(nullptr) {
|
TcpConnection::TcpConnection(Dispatcher& dispatcher, int socket) : dispatcher(&dispatcher), connection(socket), stopped(false), readContext(nullptr), writeContext(nullptr) {
|
||||||
int val = 1;
|
|
||||||
if (setsockopt(connection, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof val) == -1) {
|
|
||||||
throw std::runtime_error("TcpConnection::TcpConnection, setsockopt failed, result=" + std::to_string(errno));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,8 @@ const CheckpointData CHECKPOINTS[] = {
|
||||||
{667000, "a020c8fcaa567845d04b520bb7ebe721e097a9bed2bdb8971081f933b5b42995"},
|
{667000, "a020c8fcaa567845d04b520bb7ebe721e097a9bed2bdb8971081f933b5b42995"},
|
||||||
{689000, "212ec2698c5ebd15d6242d59f36c2d186d11bb47c58054f476dd8e6b1c7f0008"},
|
{689000, "212ec2698c5ebd15d6242d59f36c2d186d11bb47c58054f476dd8e6b1c7f0008"},
|
||||||
{713000, "a03f836c4a19f907cd6cac095eb6f56f5279ca2d1303fb7f826750dcb9025495"},
|
{713000, "a03f836c4a19f907cd6cac095eb6f56f5279ca2d1303fb7f826750dcb9025495"},
|
||||||
{750300, "5117631dbeb5c14748a91127a515ecbf13f6849e14fda7ee03cd55da41f1710c"}
|
{750300, "5117631dbeb5c14748a91127a515ecbf13f6849e14fda7ee03cd55da41f1710c"},
|
||||||
|
{780000, "8dd55a9bae429e3685b90317281e633917023d3512eb7f37372209d1a5fc1070"}
|
||||||
};
|
};
|
||||||
} // CryptoNote
|
} // CryptoNote
|
||||||
|
|
||||||
|
|
|
@ -435,7 +435,11 @@ namespace CryptoNote
|
||||||
m_idleTimer.stop();
|
m_idleTimer.stop();
|
||||||
m_timedSyncTimer.stop();
|
m_timedSyncTimer.stop();
|
||||||
|
|
||||||
logger(INFO) << "Stopping " << m_connections.size() << " connections";
|
logger(INFO) << "Stopping " << m_connections.size() + m_raw_connections.size() << " connections";
|
||||||
|
|
||||||
|
for (auto& conn : m_raw_connections) {
|
||||||
|
conn.second.connection.stop();
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& conn : m_connections) {
|
for (auto& conn : m_connections) {
|
||||||
conn.second.connection.stop();
|
conn.second.connection.stop();
|
||||||
|
@ -671,32 +675,44 @@ namespace CryptoNote
|
||||||
ctx.m_is_income = false;
|
ctx.m_is_income = false;
|
||||||
ctx.m_started = time(nullptr);
|
ctx.m_started = time(nullptr);
|
||||||
|
|
||||||
CryptoNote::LevinProtocol proto(ctx.connection);
|
auto raw = m_raw_connections.emplace(ctx.m_connection_id, std::move(ctx)).first;
|
||||||
|
try {
|
||||||
|
CryptoNote::LevinProtocol proto(raw->second.connection);
|
||||||
|
|
||||||
if (!handshake(proto, ctx, just_take_peerlist)) {
|
if (!handshake(proto, raw->second, just_take_peerlist)) {
|
||||||
logger(WARNING) << "Failed to HANDSHAKE with peer " << na;
|
logger(WARNING) << "Failed to HANDSHAKE with peer " << na;
|
||||||
return false;
|
m_raw_connections.erase(raw);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
m_raw_connections.erase(raw);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (just_take_peerlist) {
|
if (just_take_peerlist) {
|
||||||
logger(Logging::DEBUGGING, Logging::BRIGHT_GREEN) << ctx << "CONNECTION HANDSHAKED OK AND CLOSED.";
|
logger(Logging::DEBUGGING, Logging::BRIGHT_GREEN) << raw->second << "CONNECTION HANDSHAKED OK AND CLOSED.";
|
||||||
|
m_raw_connections.erase(raw);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
peerlist_entry pe_local = AUTO_VAL_INIT(pe_local);
|
peerlist_entry pe_local = AUTO_VAL_INIT(pe_local);
|
||||||
pe_local.adr = na;
|
pe_local.adr = na;
|
||||||
pe_local.id = ctx.peer_id;
|
pe_local.id = raw->second.peer_id;
|
||||||
time(&pe_local.last_seen);
|
time(&pe_local.last_seen);
|
||||||
m_peerlist.append_with_peer_white(pe_local);
|
m_peerlist.append_with_peer_white(pe_local);
|
||||||
|
|
||||||
if (m_stop) {
|
if (m_stop) {
|
||||||
|
m_raw_connections.erase(raw);
|
||||||
throw System::InterruptedException();
|
throw System::InterruptedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = m_connections.emplace(ctx.m_connection_id, std::move(ctx)).first;
|
auto iter = m_connections.emplace(raw->first, std::move(raw->second)).first;
|
||||||
|
m_raw_connections.erase(raw);
|
||||||
|
const boost::uuids::uuid& connectionId = iter->first;
|
||||||
|
p2p_connection_context& connectionContext = iter->second;
|
||||||
|
|
||||||
++m_spawnCount;
|
++m_spawnCount;
|
||||||
m_dispatcher.spawn(std::bind(&node_server::connectionHandler, this, iter));
|
m_dispatcher.spawn(std::bind(&node_server::connectionHandler, this, std::cref(connectionId), std::ref(connectionContext)));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (System::InterruptedException&) {
|
} catch (System::InterruptedException&) {
|
||||||
|
@ -1219,9 +1235,11 @@ namespace CryptoNote
|
||||||
ctx.m_remote_port = addressAndPort.second;
|
ctx.m_remote_port = addressAndPort.second;
|
||||||
|
|
||||||
auto iter = m_connections.emplace(ctx.m_connection_id, std::move(ctx)).first;
|
auto iter = m_connections.emplace(ctx.m_connection_id, std::move(ctx)).first;
|
||||||
|
const boost::uuids::uuid& connectionId = iter->first;
|
||||||
|
p2p_connection_context& connection = iter->second;
|
||||||
|
|
||||||
++m_spawnCount;
|
++m_spawnCount;
|
||||||
m_dispatcher.spawn(std::bind(&node_server::connectionHandler, this, iter));
|
m_dispatcher.spawn(std::bind(&node_server::connectionHandler, this, std::cref(connectionId), std::ref(connection)));
|
||||||
}
|
}
|
||||||
} catch (System::InterruptedException&) {
|
} catch (System::InterruptedException&) {
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -1274,10 +1292,9 @@ namespace CryptoNote
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void node_server::connectionHandler(ConnectionIterator connIter) {
|
void node_server::connectionHandler(const boost::uuids::uuid& connectionId, p2p_connection_context& ctx) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto& ctx = connIter->second;
|
|
||||||
on_connection_new(ctx);
|
on_connection_new(ctx);
|
||||||
|
|
||||||
LevinProtocol proto(ctx.connection);
|
LevinProtocol proto(ctx.connection);
|
||||||
|
@ -1320,10 +1337,10 @@ namespace CryptoNote
|
||||||
logger(WARNING) << "Exception in connectionHandler: " << e.what();
|
logger(WARNING) << "Exception in connectionHandler: " << e.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
connIter->second.writeLatch.wait();
|
ctx.writeLatch.wait();
|
||||||
|
|
||||||
on_connection_close(connIter->second);
|
on_connection_close(ctx);
|
||||||
m_connections.erase(connIter);
|
m_connections.erase(connectionId);
|
||||||
|
|
||||||
if (--m_spawnCount == 0) {
|
if (--m_spawnCount == 0) {
|
||||||
m_shutdownCompleteEvent.set();
|
m_shutdownCompleteEvent.set();
|
||||||
|
|
|
@ -171,10 +171,11 @@ namespace CryptoNote
|
||||||
|
|
||||||
typedef std::unordered_map<boost::uuids::uuid, p2p_connection_context, boost::hash<boost::uuids::uuid>> ConnectionContainer;
|
typedef std::unordered_map<boost::uuids::uuid, p2p_connection_context, boost::hash<boost::uuids::uuid>> ConnectionContainer;
|
||||||
typedef ConnectionContainer::iterator ConnectionIterator;
|
typedef ConnectionContainer::iterator ConnectionIterator;
|
||||||
|
ConnectionContainer m_raw_connections;
|
||||||
ConnectionContainer m_connections;
|
ConnectionContainer m_connections;
|
||||||
|
|
||||||
void acceptLoop();
|
void acceptLoop();
|
||||||
void connectionHandler(ConnectionIterator connIter);
|
void connectionHandler(const boost::uuids::uuid& connectionId, p2p_connection_context& connection);
|
||||||
void onIdle();
|
void onIdle();
|
||||||
void timedSyncLoop();
|
void timedSyncLoop();
|
||||||
|
|
||||||
|
|
|
@ -791,7 +791,7 @@ bool simple_wallet::listTransfers(const std::vector<std::string>& args) {
|
||||||
for (size_t trantransactionNumber = 0; trantransactionNumber < transactionsCount; ++trantransactionNumber) {
|
for (size_t trantransactionNumber = 0; trantransactionNumber < transactionsCount; ++trantransactionNumber) {
|
||||||
TransactionInfo txInfo;
|
TransactionInfo txInfo;
|
||||||
m_wallet->getTransaction(trantransactionNumber, txInfo);
|
m_wallet->getTransaction(trantransactionNumber, txInfo);
|
||||||
if (txInfo.state != TransactionState::Active) {
|
if (txInfo.state != TransactionState::Active || txInfo.blockHeight == UNCONFIRMED_TRANSACTION_HEIGHT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,6 @@ private:
|
||||||
INode& m_node;
|
INode& m_node;
|
||||||
const crypto::hash m_genesisBlockHash;
|
const crypto::hash m_genesisBlockHash;
|
||||||
|
|
||||||
std::vector<crypto::hash> knownTxIds;
|
|
||||||
crypto::hash lastBlockId;
|
crypto::hash lastBlockId;
|
||||||
|
|
||||||
State m_currentState;
|
State m_currentState;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#define BUILD_COMMIT_ID "@VERSION@"
|
#define BUILD_COMMIT_ID "@VERSION@"
|
||||||
#define PROJECT_VERSION "1.0.4"
|
#define PROJECT_VERSION "1.0.4.1"
|
||||||
#define PROJECT_VERSION_BUILD_NO "461"
|
#define PROJECT_VERSION_BUILD_NO "466"
|
||||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
||||||
|
|
|
@ -16,14 +16,15 @@
|
||||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
#include "serialization/binary_utils.h"
|
|
||||||
#include "WalletUtils.h"
|
|
||||||
#include "WalletSerializer.h"
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "serialization/binary_utils.h"
|
||||||
|
#include "WalletHelper.h"
|
||||||
#include "WalletSerialization.h"
|
#include "WalletSerialization.h"
|
||||||
|
#include "WalletSerializer.h"
|
||||||
|
#include "WalletUtils.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ private:
|
||||||
std::promise<std::error_code> promise;
|
std::promise<std::error_code> promise;
|
||||||
std::future<std::error_code> future;
|
std::future<std::error_code> future;
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace
|
} //namespace
|
||||||
|
|
||||||
namespace CryptoNote {
|
namespace CryptoNote {
|
||||||
|
@ -125,7 +127,6 @@ Wallet::Wallet(const CryptoNote::Currency& currency, INode& node) :
|
||||||
m_onInitSyncStarter(new SyncStarter(m_blockchainSync))
|
m_onInitSyncStarter(new SyncStarter(m_blockchainSync))
|
||||||
{
|
{
|
||||||
addObserver(m_onInitSyncStarter.get());
|
addObserver(m_onInitSyncStarter.get());
|
||||||
m_blockchainSync.addObserver(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet::~Wallet() {
|
Wallet::~Wallet() {
|
||||||
|
@ -139,10 +140,10 @@ Wallet::~Wallet() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_blockchainSync.removeObserver(this);
|
m_blockchainSync.removeObserver(this);
|
||||||
m_blockchainSync.stop();
|
m_blockchainSync.stop();
|
||||||
m_asyncContextCounter.waitAsyncContextsFinish();
|
m_asyncContextCounter.waitAsyncContextsFinish();
|
||||||
m_sender.release();
|
m_sender.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wallet::addObserver(IWalletObserver* observer) {
|
void Wallet::addObserver(IWalletObserver* observer) {
|
||||||
|
@ -234,6 +235,8 @@ void Wallet::initSync() {
|
||||||
|
|
||||||
m_sender.reset(new WalletTransactionSender(m_currency, m_transactionsCache, m_account.get_keys(), *m_transferDetails));
|
m_sender.reset(new WalletTransactionSender(m_currency, m_transactionsCache, m_account.get_keys(), *m_transferDetails));
|
||||||
m_state = INITIALIZED;
|
m_state = INITIALIZED;
|
||||||
|
|
||||||
|
m_blockchainSync.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wallet::doLoad(std::istream& source) {
|
void Wallet::doLoad(std::istream& source) {
|
||||||
|
@ -248,20 +251,18 @@ void Wallet::doLoad(std::istream& source) {
|
||||||
initSync();
|
initSync();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!cache.empty()) {
|
if (!cache.empty()) {
|
||||||
std::stringstream stream(cache);
|
std::stringstream stream(cache);
|
||||||
m_transfersSync.load(stream);
|
m_transfersSync.load(stream);
|
||||||
}
|
}
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
// ignore cache loading errors
|
// ignore cache loading errors
|
||||||
}
|
}
|
||||||
}
|
} catch (std::system_error& e) {
|
||||||
catch (std::system_error& e) {
|
|
||||||
runAtomic(m_cacheMutex, [this] () {this->m_state = Wallet::NOT_INITIALIZED;} );
|
runAtomic(m_cacheMutex, [this] () {this->m_state = Wallet::NOT_INITIALIZED;} );
|
||||||
m_observerManager.notify(&IWalletObserver::initCompleted, e.code());
|
m_observerManager.notify(&IWalletObserver::initCompleted, e.code());
|
||||||
return;
|
return;
|
||||||
}
|
} catch (std::exception&) {
|
||||||
catch (std::exception&) {
|
|
||||||
runAtomic(m_cacheMutex, [this] () {this->m_state = Wallet::NOT_INITIALIZED;} );
|
runAtomic(m_cacheMutex, [this] () {this->m_state = Wallet::NOT_INITIALIZED;} );
|
||||||
m_observerManager.notify(&IWalletObserver::initCompleted, make_error_code(CryptoNote::error::INTERNAL_WALLET_ERROR));
|
m_observerManager.notify(&IWalletObserver::initCompleted, make_error_code(CryptoNote::error::INTERNAL_WALLET_ERROR));
|
||||||
return;
|
return;
|
||||||
|
@ -295,31 +296,39 @@ void Wallet::shutdown() {
|
||||||
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
std::unique_lock<std::mutex> lock(m_cacheMutex);
|
||||||
m_isStopping = false;
|
m_isStopping = false;
|
||||||
m_state = NOT_INITIALIZED;
|
m_state = NOT_INITIALIZED;
|
||||||
|
|
||||||
|
const AccountAddress& accountAddress = reinterpret_cast<const AccountAddress&>(m_account.get_keys().m_account_address);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wallet::reset() {
|
void Wallet::reset() {
|
||||||
InitWaiter initWaiter;
|
InitWaiter initWaiter;
|
||||||
SaveWaiter saveWaiter;
|
SaveWaiter saveWaiter;
|
||||||
|
WalletHelper::IWalletRemoveObserverGuard initGuarantee(*this, initWaiter);
|
||||||
addObserver(&initWaiter);
|
WalletHelper::IWalletRemoveObserverGuard saveGuarantee(*this, saveWaiter);
|
||||||
addObserver(&saveWaiter);
|
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
try {
|
try {
|
||||||
save(ss, false, false);
|
save(ss, false, false);
|
||||||
|
|
||||||
auto saveError = saveWaiter.waitSave();
|
auto saveError = saveWaiter.waitSave();
|
||||||
if (!saveError) {
|
if (!saveError) {
|
||||||
shutdown();
|
shutdown();
|
||||||
initAndLoad(ss, m_password);
|
initAndLoad(ss, m_password);
|
||||||
initWaiter.waitInit();
|
initWaiter.waitInit();
|
||||||
|
}
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
std::cout << "exception in reset: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
} catch (std::exception&) {
|
|
||||||
}
|
|
||||||
|
|
||||||
removeObserver(&saveWaiter);
|
|
||||||
removeObserver(&initWaiter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wallet::save(std::ostream& destination, bool saveDetailed, bool saveCache) {
|
void Wallet::save(std::ostream& destination, bool saveDetailed, bool saveCache) {
|
||||||
|
|
|
@ -123,5 +123,9 @@ void WalletUnconfirmedTransactions::collectUsedOutputs() {
|
||||||
m_usedOutputs = std::move(used);
|
m_usedOutputs = std::move(used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WalletUnconfirmedTransactions::reset() {
|
||||||
|
m_unconfirmedTxs.clear();
|
||||||
|
m_usedOutputs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace CryptoNote */
|
} /* namespace CryptoNote */
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
uint64_t countUnconfirmedOutsAmount() const;
|
uint64_t countUnconfirmedOutsAmount() const;
|
||||||
uint64_t countUnconfirmedTransactionsAmount() const;
|
uint64_t countUnconfirmedTransactionsAmount() const;
|
||||||
bool isUsed(const TransactionOutputInformation& out) const;
|
bool isUsed(const TransactionOutputInformation& out) const;
|
||||||
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -294,4 +294,10 @@ Transfer& WalletUserTransactionsCache::getTransfer(TransferId transferId) {
|
||||||
return m_transfers.at(transferId);
|
return m_transfers.at(transferId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WalletUserTransactionsCache::reset() {
|
||||||
|
m_transactions.clear();
|
||||||
|
m_transfers.clear();
|
||||||
|
m_unconfirmedTransactions.reset();
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace CryptoNote
|
} //namespace CryptoNote
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
Transfer& getTransfer(TransferId transferId);
|
Transfer& getTransfer(TransferId transferId);
|
||||||
|
|
||||||
bool isUsed(const TransactionOutputInformation& out) const;
|
bool isUsed(const TransactionOutputInformation& out) const;
|
||||||
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "EventWaiter.h"
|
#include "EventWaiter.h"
|
||||||
#include "INode.h"
|
#include "INode.h"
|
||||||
#include "wallet/Wallet.h"
|
#include "wallet/Wallet.h"
|
||||||
|
#include "wallet/WalletHelper.h"
|
||||||
#include "cryptonote_core/account.h"
|
#include "cryptonote_core/account.h"
|
||||||
#include "cryptonote_core/Currency.h"
|
#include "cryptonote_core/Currency.h"
|
||||||
|
|
||||||
|
@ -285,7 +286,7 @@ void WalletApi::TestSendMoney(int64_t transferAmount, uint64_t fee, uint64_t mix
|
||||||
bob->initAndGenerate("pass2");
|
bob->initAndGenerate("pass2");
|
||||||
|
|
||||||
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(bobWalletObserver.get()));
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(bobWalletObserver.get()));
|
||||||
ASSERT_NO_FATAL_FAILURE(TransferMoney(*alice, *bob, transferAmount, fee, 0, ""));
|
ASSERT_NO_FATAL_FAILURE(TransferMoney(*alice, *bob, transferAmount, fee, mixIn, ""));
|
||||||
ASSERT_NO_FATAL_FAILURE(WaitWalletSend(aliceWalletObserver.get()));
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSend(aliceWalletObserver.get()));
|
||||||
|
|
||||||
generator.generateEmptyBlocks(10);
|
generator.generateEmptyBlocks(10);
|
||||||
|
@ -1327,3 +1328,344 @@ TEST_F(WalletApi, DISABLED_loadingBrokenCache) {
|
||||||
ASSERT_NO_FATAL_FAILURE(WaitWalletLoad(aliceWalletObserver.get(), result));
|
ASSERT_NO_FATAL_FAILURE(WaitWalletLoad(aliceWalletObserver.get(), result));
|
||||||
ASSERT_EQ(result.value(), 0);
|
ASSERT_EQ(result.value(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, shutdownAllowsInitializeWalletWithTheSameKeys) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
CryptoNote::WalletAccountKeys accountKeys;
|
||||||
|
alice->getAccountKeys(accountKeys);
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
alice->initWithKeys(accountKeys, "pass");
|
||||||
|
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(1, alice->getTransactionCount());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, shutdownAllowsInitializeWalletWithDifferentKeys) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, alice->getTransactionCount());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class WalletSynchronizationProgressUpdatedObserver : public CryptoNote::IWalletObserver {
|
||||||
|
public:
|
||||||
|
virtual void synchronizationProgressUpdated(uint64_t current, uint64_t /*total*/) override {
|
||||||
|
m_current = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t m_current = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, shutdownDoesNotRemoveObservers) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
WalletSynchronizationProgressUpdatedObserver observer;
|
||||||
|
CryptoNote::WalletHelper::IWalletRemoveObserverGuard observerGuard(*alice, observer);
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
observer.m_current = 0;
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(5, observer.m_current);
|
||||||
|
|
||||||
|
observerGuard.removeObserver();
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class WalletTransactionEventCounter : public CryptoNote::IWalletObserver {
|
||||||
|
public:
|
||||||
|
virtual void externalTransactionCreated(CryptoNote::TransactionId /*transactionId*/) override {
|
||||||
|
++m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void transactionUpdated(CryptoNote::TransactionId /*transactionId*/) override {
|
||||||
|
++m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t m_count = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, afterShutdownAndInitWalletDoesNotSendNotificationsRelatedToOldAddress) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
std::string aliceAddress1 = alice->getAddress();
|
||||||
|
CryptoNote::WalletAccountKeys accountKeys1;
|
||||||
|
alice->getAccountKeys(accountKeys1);
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
std::string aliceAddress2 = alice->getAddress();
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
alice->initWithKeys(accountKeys1, "pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
WalletTransactionEventCounter observer;
|
||||||
|
CryptoNote::WalletHelper::IWalletRemoveObserverGuard observerGuard(*alice, observer);
|
||||||
|
|
||||||
|
prepareBobWallet();
|
||||||
|
bob->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(bobWalletObserver.get()));
|
||||||
|
GetOneBlockReward(*bob);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
bobNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(bobWalletObserver.get()));
|
||||||
|
|
||||||
|
std::vector<CryptoNote::Transfer> transfers;
|
||||||
|
transfers.push_back({ aliceAddress1, TEST_BLOCK_REWARD / 10 });
|
||||||
|
transfers.push_back({ aliceAddress2, TEST_BLOCK_REWARD / 5 });
|
||||||
|
bob->sendTransaction(transfers, m_currency.minimumFee());
|
||||||
|
std::error_code sendResult;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSend(bobWalletObserver.get(), sendResult));
|
||||||
|
|
||||||
|
generator.generateEmptyBlocks(1);
|
||||||
|
bobNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(bobWalletObserver.get()));
|
||||||
|
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(1, observer.m_count);
|
||||||
|
|
||||||
|
observerGuard.removeObserver();
|
||||||
|
bob->shutdown();
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetDoesNotChangeAddress) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
auto expectedAddress = alice->getAddress();
|
||||||
|
alice->reset();
|
||||||
|
ASSERT_EQ(expectedAddress, alice->getAddress());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetDoesNotChangeAccountKeys) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
CryptoNote::WalletAccountKeys expectedAccountKeys;
|
||||||
|
alice->getAccountKeys(expectedAccountKeys);
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
|
||||||
|
CryptoNote::WalletAccountKeys actualAccountKeys;
|
||||||
|
alice->getAccountKeys(actualAccountKeys);
|
||||||
|
|
||||||
|
ASSERT_EQ(expectedAccountKeys.spendPublicKey, actualAccountKeys.spendPublicKey);
|
||||||
|
ASSERT_EQ(expectedAccountKeys.spendSecretKey, actualAccountKeys.spendSecretKey);
|
||||||
|
ASSERT_EQ(expectedAccountKeys.viewPublicKey, actualAccountKeys.viewPublicKey);
|
||||||
|
ASSERT_EQ(expectedAccountKeys.viewSecretKey, actualAccountKeys.viewSecretKey);
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetDoesNotRemoveObservers) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
WalletSynchronizationProgressUpdatedObserver observer;
|
||||||
|
CryptoNote::WalletHelper::IWalletRemoveObserverGuard observerGuard(*alice, observer);
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
observer.m_current = 0;
|
||||||
|
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(5, observer.m_current);
|
||||||
|
|
||||||
|
observerGuard.removeObserver();
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetDoesNotChangePassword) {
|
||||||
|
std::string password = "password";
|
||||||
|
std::string newPassword = "new_password";
|
||||||
|
|
||||||
|
alice->initAndGenerate(password);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
ASSERT_TRUE(static_cast<bool>(alice->changePassword(newPassword, password)));
|
||||||
|
ASSERT_FALSE(static_cast<bool>(alice->changePassword(password, newPassword)));
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetClearsPendingBalance) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(TEST_BLOCK_REWARD, alice->pendingBalance());
|
||||||
|
alice->reset();
|
||||||
|
ASSERT_EQ(0, alice->pendingBalance());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetClearsActualBalance) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(TEST_BLOCK_REWARD, alice->actualBalance());
|
||||||
|
alice->reset();
|
||||||
|
ASSERT_EQ(0, alice->actualBalance());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetClearsTransactionHistory) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(1, alice->getTransactionCount());
|
||||||
|
alice->reset();
|
||||||
|
ASSERT_EQ(0, alice->getTransactionCount());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetClearsTransfersHistory) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->sendTransaction({ alice->getAddress(), 100 }, m_currency.minimumFee());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSend(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(1, alice->getTransferCount());
|
||||||
|
alice->reset();
|
||||||
|
ASSERT_EQ(0, alice->getTransferCount());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetAndSyncRestorePendingBalance) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(TEST_BLOCK_REWARD, alice->pendingBalance());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetAndSyncRestoreActualBalance) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(TEST_BLOCK_REWARD, alice->actualBalance());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetAndSyncRestoreTransactions) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(1, alice->getTransactionCount());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, resetAndSyncDoNotRestoreTransfers) {
|
||||||
|
alice->initAndGenerate("pass");
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
GetOneBlockReward(*alice);
|
||||||
|
generator.generateEmptyBlocks(10);
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->sendTransaction({ alice->getAddress(), 100 }, m_currency.minimumFee());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSend(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
alice->reset();
|
||||||
|
aliceNode->updateObservers();
|
||||||
|
ASSERT_NO_FATAL_FAILURE(WaitWalletSync(aliceWalletObserver.get()));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, alice->getTransferCount());
|
||||||
|
|
||||||
|
alice->shutdown();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue