Simplewallet improvements

This commit is contained in:
Antonio Juarez 2015-07-09 15:52:47 +01:00
parent ad291f5285
commit 6d45be9ec0
14 changed files with 439 additions and 58 deletions

View file

@ -35,7 +35,10 @@ namespace {
void handleSignal() {
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();
}
@ -75,6 +78,7 @@ namespace tools {
#else
signal(SIGINT, posixHandler);
signal(SIGTERM, posixHandler);
signal(SIGPIPE, SIG_IGN);
m_handler = t;
return true;
#endif

View file

@ -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) {
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));
}
}
}

View file

@ -150,7 +150,8 @@ const CheckpointData CHECKPOINTS[] = {
{667000, "a020c8fcaa567845d04b520bb7ebe721e097a9bed2bdb8971081f933b5b42995"},
{689000, "212ec2698c5ebd15d6242d59f36c2d186d11bb47c58054f476dd8e6b1c7f0008"},
{713000, "a03f836c4a19f907cd6cac095eb6f56f5279ca2d1303fb7f826750dcb9025495"},
{750300, "5117631dbeb5c14748a91127a515ecbf13f6849e14fda7ee03cd55da41f1710c"}
{750300, "5117631dbeb5c14748a91127a515ecbf13f6849e14fda7ee03cd55da41f1710c"},
{780000, "8dd55a9bae429e3685b90317281e633917023d3512eb7f37372209d1a5fc1070"}
};
} // CryptoNote

View file

@ -435,7 +435,11 @@ namespace CryptoNote
m_idleTimer.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) {
conn.second.connection.stop();
@ -671,32 +675,44 @@ namespace CryptoNote
ctx.m_is_income = false;
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)) {
logger(WARNING) << "Failed to HANDSHAKE with peer " << na;
return false;
if (!handshake(proto, raw->second, just_take_peerlist)) {
logger(WARNING) << "Failed to HANDSHAKE with peer " << na;
m_raw_connections.erase(raw);
return false;
}
} catch (...) {
m_raw_connections.erase(raw);
throw;
}
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;
}
peerlist_entry pe_local = AUTO_VAL_INIT(pe_local);
pe_local.adr = na;
pe_local.id = ctx.peer_id;
pe_local.id = raw->second.peer_id;
time(&pe_local.last_seen);
m_peerlist.append_with_peer_white(pe_local);
if (m_stop) {
m_raw_connections.erase(raw);
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_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;
} catch (System::InterruptedException&) {
@ -1219,9 +1235,11 @@ namespace CryptoNote
ctx.m_remote_port = addressAndPort.second;
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_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 (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 {
auto& ctx = connIter->second;
on_connection_new(ctx);
LevinProtocol proto(ctx.connection);
@ -1320,10 +1337,10 @@ namespace CryptoNote
logger(WARNING) << "Exception in connectionHandler: " << e.what();
}
connIter->second.writeLatch.wait();
ctx.writeLatch.wait();
on_connection_close(connIter->second);
m_connections.erase(connIter);
on_connection_close(ctx);
m_connections.erase(connectionId);
if (--m_spawnCount == 0) {
m_shutdownCompleteEvent.set();

View file

@ -171,10 +171,11 @@ namespace CryptoNote
typedef std::unordered_map<boost::uuids::uuid, p2p_connection_context, boost::hash<boost::uuids::uuid>> ConnectionContainer;
typedef ConnectionContainer::iterator ConnectionIterator;
ConnectionContainer m_raw_connections;
ConnectionContainer m_connections;
void acceptLoop();
void connectionHandler(ConnectionIterator connIter);
void connectionHandler(const boost::uuids::uuid& connectionId, p2p_connection_context& connection);
void onIdle();
void timedSyncLoop();

View file

@ -791,7 +791,7 @@ bool simple_wallet::listTransfers(const std::vector<std::string>& args) {
for (size_t trantransactionNumber = 0; trantransactionNumber < transactionsCount; ++trantransactionNumber) {
TransactionInfo txInfo;
m_wallet->getTransaction(trantransactionNumber, txInfo);
if (txInfo.state != TransactionState::Active) {
if (txInfo.state != TransactionState::Active || txInfo.blockHeight == UNCONFIRMED_TRANSACTION_HEIGHT) {
continue;
}

View file

@ -125,7 +125,6 @@ private:
INode& m_node;
const crypto::hash m_genesisBlockHash;
std::vector<crypto::hash> knownTxIds;
crypto::hash lastBlockId;
State m_currentState;

View file

@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_VERSION "1.0.4"
#define PROJECT_VERSION_BUILD_NO "461"
#define PROJECT_VERSION "1.0.4.1"
#define PROJECT_VERSION_BUILD_NO "466"
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"

View file

@ -16,14 +16,15 @@
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
#include "Wallet.h"
#include "serialization/binary_utils.h"
#include "WalletUtils.h"
#include "WalletSerializer.h"
#include <time.h>
#include <string.h>
#include <time.h>
#include "serialization/binary_utils.h"
#include "WalletHelper.h"
#include "WalletSerialization.h"
#include "WalletSerializer.h"
#include "WalletUtils.h"
namespace {
@ -93,6 +94,7 @@ private:
std::promise<std::error_code> promise;
std::future<std::error_code> future;
};
} //namespace
namespace CryptoNote {
@ -125,7 +127,6 @@ Wallet::Wallet(const CryptoNote::Currency& currency, INode& node) :
m_onInitSyncStarter(new SyncStarter(m_blockchainSync))
{
addObserver(m_onInitSyncStarter.get());
m_blockchainSync.addObserver(this);
}
Wallet::~Wallet() {
@ -139,10 +140,10 @@ Wallet::~Wallet() {
}
}
m_blockchainSync.removeObserver(this);
m_blockchainSync.stop();
m_asyncContextCounter.waitAsyncContextsFinish();
m_sender.release();
m_blockchainSync.removeObserver(this);
m_blockchainSync.stop();
m_asyncContextCounter.waitAsyncContextsFinish();
m_sender.release();
}
void Wallet::addObserver(IWalletObserver* observer) {
@ -215,7 +216,7 @@ void Wallet::initAndLoad(std::istream& source, const std::string& password) {
m_password = password;
m_state = LOADING;
m_asyncContextCounter.addAsyncContext();
std::thread loader(&Wallet::doLoad, this, std::ref(source));
loader.detach();
@ -234,6 +235,8 @@ void Wallet::initSync() {
m_sender.reset(new WalletTransactionSender(m_currency, m_transactionsCache, m_account.get_keys(), *m_transferDetails));
m_state = INITIALIZED;
m_blockchainSync.addObserver(this);
}
void Wallet::doLoad(std::istream& source) {
@ -248,20 +251,18 @@ void Wallet::doLoad(std::istream& source) {
initSync();
try {
if (!cache.empty()) {
std::stringstream stream(cache);
m_transfersSync.load(stream);
}
if (!cache.empty()) {
std::stringstream stream(cache);
m_transfersSync.load(stream);
}
} catch (const std::exception&) {
// ignore cache loading errors
}
}
catch (std::system_error& e) {
}
} catch (std::system_error& e) {
runAtomic(m_cacheMutex, [this] () {this->m_state = Wallet::NOT_INITIALIZED;} );
m_observerManager.notify(&IWalletObserver::initCompleted, e.code());
return;
}
catch (std::exception&) {
} catch (std::exception&) {
runAtomic(m_cacheMutex, [this] () {this->m_state = Wallet::NOT_INITIALIZED;} );
m_observerManager.notify(&IWalletObserver::initCompleted, make_error_code(CryptoNote::error::INTERNAL_WALLET_ERROR));
return;
@ -295,31 +296,39 @@ void Wallet::shutdown() {
std::unique_lock<std::mutex> lock(m_cacheMutex);
m_isStopping = false;
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() {
InitWaiter initWaiter;
SaveWaiter saveWaiter;
addObserver(&initWaiter);
addObserver(&saveWaiter);
WalletHelper::IWalletRemoveObserverGuard initGuarantee(*this, initWaiter);
WalletHelper::IWalletRemoveObserverGuard saveGuarantee(*this, saveWaiter);
std::stringstream ss;
try {
save(ss, false, false);
save(ss, false, false);
auto saveError = saveWaiter.waitSave();
if (!saveError) {
shutdown();
initAndLoad(ss, m_password);
if (!saveError) {
shutdown();
initAndLoad(ss, m_password);
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) {

View file

@ -123,5 +123,9 @@ void WalletUnconfirmedTransactions::collectUsedOutputs() {
m_usedOutputs = std::move(used);
}
void WalletUnconfirmedTransactions::reset() {
m_unconfirmedTxs.clear();
m_usedOutputs.clear();
}
} /* namespace CryptoNote */

View file

@ -64,6 +64,7 @@ public:
uint64_t countUnconfirmedOutsAmount() const;
uint64_t countUnconfirmedTransactionsAmount() const;
bool isUsed(const TransactionOutputInformation& out) const;
void reset();
private:

View file

@ -293,5 +293,11 @@ void WalletUserTransactionsCache::updateUnconfirmedTransactions() {
Transfer& WalletUserTransactionsCache::getTransfer(TransferId transferId) {
return m_transfers.at(transferId);
}
void WalletUserTransactionsCache::reset() {
m_transactions.clear();
m_transfers.clear();
m_unconfirmedTransactions.reset();
}
} //namespace CryptoNote

View file

@ -57,6 +57,7 @@ public:
Transfer& getTransfer(TransferId transferId);
bool isUsed(const TransactionOutputInformation& out) const;
void reset();
private:

View file

@ -24,6 +24,7 @@
#include "EventWaiter.h"
#include "INode.h"
#include "wallet/Wallet.h"
#include "wallet/WalletHelper.h"
#include "cryptonote_core/account.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");
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()));
generator.generateEmptyBlocks(10);
@ -1327,3 +1328,344 @@ TEST_F(WalletApi, DISABLED_loadingBrokenCache) {
ASSERT_NO_FATAL_FAILURE(WaitWalletLoad(aliceWalletObserver.get(), result));
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();
}