diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 9bb7f056..16321a5a 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -167,7 +167,7 @@ uint64_t Wallet::maximumAllowedAmount() ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false), - m_wallet2Callback(nullptr) + m_wallet2Callback(nullptr), m_recoveringFromSeed(false) { m_wallet = new tools::wallet2(testnet); m_history = new TransactionHistoryImpl(this); @@ -197,7 +197,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co { clearStatus(); - + m_recoveringFromSeed = false; bool keys_file_exists; bool wallet_file_exists; tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); @@ -234,6 +234,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co bool WalletImpl::open(const std::string &path, const std::string &password) { clearStatus(); + m_recoveringFromSeed = false; try { // TODO: handle "deprecated" m_wallet->load(path, password); @@ -258,6 +259,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &seed) return false; } + m_recoveringFromSeed = true; crypto::secret_key recovery_key; std::string old_language; if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) { @@ -270,6 +272,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &seed) m_wallet->set_seed_language(old_language); m_wallet->generate(path, "", recovery_key, true, false); // TODO: wallet->init(daemon_address); + } catch (const std::exception &e) { m_status = Status_Error; m_errorString = e.what(); @@ -747,7 +750,7 @@ bool WalletImpl::isNewWallet() const // in case wallet created without daemon connection, closed and opened again, // it's the same case as if it created from scratch, i.e. we need "fast sync" // with the daemon (pull hashes instead of pull blocks) - return !(blockChainHeight() > 1); + return !(blockChainHeight() > 1 || m_recoveringFromSeed); } void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 09db05d0..5706b2bf 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -128,6 +128,10 @@ private: boost::mutex m_refreshMutex2; boost::condition_variable m_refreshCV; boost::thread m_refreshThread; + // flag indicating wallet is recovering from seed + // so it shouldn't be considered as new and pull blocks (slow-refresh) + // instead of pulling hashes (fast-refresh) + bool m_recoveringFromSeed; }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index a4b88140..45a94b4d 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -950,7 +950,7 @@ TEST_F(WalletTest2, WalletCallbackReceived) ASSERT_TRUE(wallet_dst->refresh()); uint64_t balance = wallet_dst->balance(); std::cout << "** Balance dst1: " << wallet_dst->displayAmount(wallet_dst->balance()) << std::endl; - MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst); + std::unique_ptr wallet_dst_listener (new MyWalletListener(wallet_dst)); uint64_t amount = AMOUNT_1XMR * 5; std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address(); @@ -994,7 +994,7 @@ TEST_F(WalletTest2, WalletCallbackNewBlock) std::cout << "** Block height: " << bc1 << std::endl; - MyWalletListener * wallet_listener = new MyWalletListener(wallet_src); + std::unique_ptr wallet_listener (new MyWalletListener(wallet_src)); // wait max 4 min for new block std::chrono::seconds wait_for = std::chrono::seconds(60*4); @@ -1014,10 +1014,7 @@ TEST_F(WalletManagerMainnetTest, CreateOpenAndRefreshWalletMainNetSync) { Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG); - MyWalletListener * wallet_listener = new MyWalletListener(wallet); - std::chrono::seconds wait_for = std::chrono::seconds(30); - std::unique_lock lock (wallet_listener->mutex); - // wallet->initAsync(MAINNET_DAEMON_ADDRESS, 0); + std::unique_ptr wallet_listener (new MyWalletListener(wallet)); wallet->init(MAINNET_DAEMON_ADDRESS, 0); std::cerr << "TEST: waiting on refresh lock...\n"; //wallet_listener->cv_refresh.wait_for(lock, wait_for); @@ -1032,16 +1029,20 @@ TEST_F(WalletManagerMainnetTest, CreateOpenAndRefreshWalletMainNetSync) TEST_F(WalletManagerMainnetTest, CreateAndRefreshWalletMainNetAsync) { + // supposing 120 seconds should be enough for fast refresh + int SECONDS_TO_REFRESH = 120; Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG); - MyWalletListener * wallet_listener = new MyWalletListener(wallet); - std::chrono::seconds wait_for = std::chrono::seconds(30); + std::unique_ptr wallet_listener (new MyWalletListener(wallet)); + + std::chrono::seconds wait_for = std::chrono::seconds(SECONDS_TO_REFRESH); std::unique_lock lock (wallet_listener->mutex); wallet->initAsync(MAINNET_DAEMON_ADDRESS, 0); // wallet->init(MAINNET_DAEMON_ADDRESS, 0); std::cerr << "TEST: waiting on refresh lock...\n"; wallet_listener->cv_refresh.wait_for(lock, wait_for); std::cerr << "TEST: refresh lock acquired...\n"; + ASSERT_TRUE(wallet->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet_listener->refresh_triggered); ASSERT_TRUE(wallet->connected()); ASSERT_TRUE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight()); @@ -1052,26 +1053,67 @@ TEST_F(WalletManagerMainnetTest, CreateAndRefreshWalletMainNetAsync) TEST_F(WalletManagerMainnetTest, OpenAndRefreshWalletMainNetAsync) { + // supposing 120 seconds should be enough for fast refresh + int SECONDS_TO_REFRESH = 120; Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG); - wmgr->closeWallet(wallet); wallet = wmgr->openWallet(WALLET_NAME_MAINNET, ""); - MyWalletListener * wallet_listener = new MyWalletListener(wallet); - std::chrono::seconds wait_for = std::chrono::seconds(30); + std::unique_ptr wallet_listener (new MyWalletListener(wallet)); + + std::chrono::seconds wait_for = std::chrono::seconds(SECONDS_TO_REFRESH); std::unique_lock lock (wallet_listener->mutex); wallet->initAsync(MAINNET_DAEMON_ADDRESS, 0); // wallet->init(MAINNET_DAEMON_ADDRESS, 0); std::cerr << "TEST: waiting on refresh lock...\n"; wallet_listener->cv_refresh.wait_for(lock, wait_for); std::cerr << "TEST: refresh lock acquired...\n"; + ASSERT_TRUE(wallet->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet_listener->refresh_triggered); ASSERT_TRUE(wallet->connected()); ASSERT_TRUE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight()); std::cerr << "TEST: closing wallet...\n"; wmgr->closeWallet(wallet); + } +TEST_F(WalletManagerMainnetTest, RecoverAndRefreshWalletMainNetAsync) +{ + + // supposing 120 seconds should be enough for fast refresh + int SECONDS_TO_REFRESH = 120; + Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG); + std::string seed = wallet->seed(); + std::string address = wallet->address(); + wmgr->closeWallet(wallet); + + // deleting wallet files + Utils::deleteWallet(WALLET_NAME_MAINNET); + // ..and recovering wallet from seed + + wallet = wmgr->recoveryWallet(WALLET_NAME_MAINNET, seed); + ASSERT_TRUE(wallet->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet->address() == address); + std::unique_ptr wallet_listener (new MyWalletListener(wallet)); + std::chrono::seconds wait_for = std::chrono::seconds(SECONDS_TO_REFRESH); + std::unique_lock lock (wallet_listener->mutex); + wallet->initAsync(MAINNET_DAEMON_ADDRESS, 0); + // wallet->init(MAINNET_DAEMON_ADDRESS, 0); + std::cerr << "TEST: waiting on refresh lock...\n"; + + // here we wait for 120 seconds and test if wallet doesn't syncrnonize blockchain completely, + // as it needs much more than 120 seconds for mainnet + + wallet_listener->cv_refresh.wait_for(lock, wait_for); + ASSERT_TRUE(wallet->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_FALSE(wallet_listener->refresh_triggered); + ASSERT_TRUE(wallet->connected()); + ASSERT_FALSE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight()); + std::cerr << "TEST: closing wallet...\n"; + wmgr->closeWallet(wallet); + std::cerr << "TEST: wallet closed\n"; + +}