From 6d32a3d16b8bb1bf2a51a41ce9f826cf31d02352 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Jul 2016 12:47:01 +0300 Subject: [PATCH] wallet_api: async init, Wallet::connected status, log level --- src/wallet/api/wallet.cpp | 54 ++++++++++----- src/wallet/api/wallet.h | 2 + src/wallet/api/wallet_manager.cpp | 5 ++ src/wallet/wallet2_api.h | 50 ++++++++++++-- tests/libwallet_api_tests/main.cpp | 101 +++++++++++++++++++++++------ 5 files changed, 173 insertions(+), 39 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e75f5afd..2322cac7 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -76,7 +76,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback virtual void on_new_block(uint64_t height, const cryptonote::block& block) { // TODO; - LOG_PRINT_L0(__FUNCTION__ << ": new block. height: " << height); + LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height); } virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) @@ -85,7 +85,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx)); uint64_t amount = tx.vout[out_index].amount; - LOG_PRINT_L0(__FUNCTION__ << ": money received. height: " << height + LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height << ", tx: " << tx_hash << ", amount: " << print_money(amount)); if (m_listener) { @@ -100,7 +100,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback // TODO; std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx)); uint64_t amount = in_tx.vout[out_index].amount; - LOG_PRINT_L0(__FUNCTION__ << ": money spent. height: " << height + LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height << ", tx: " << tx_hash << ", amount: " << print_money(amount)); if (m_listener) { @@ -121,6 +121,7 @@ Wallet::~Wallet() {} WalletListener::~WalletListener() {} + string Wallet::displayAmount(uint64_t amount) { return cryptonote::print_money(amount); @@ -269,8 +270,12 @@ bool WalletImpl::close() clearStatus(); bool result = false; try { + // LOG_PRINT_L0("Calling wallet::store..."); m_wallet->store(); + // LOG_PRINT_L0("wallet::store done"); + // LOG_PRINT_L0("Calling wallet::stop..."); m_wallet->stop(); + // LOG_PRINT_L0("wallet::stop done"); result = true; } catch (const std::exception &e) { m_status = Status_Error; @@ -366,21 +371,30 @@ string WalletImpl::keysFilename() const bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) { clearStatus(); - try { - m_wallet->init(daemon_address, upper_transaction_size_limit); - if (Utils::isAddressLocal(daemon_address)) { - this->setTrustedDaemon(true); - } - refresh(); - } catch (const std::exception &e) { - LOG_ERROR("Error initializing wallet: " << e.what()); - m_status = Status_Error; - m_errorString = e.what(); - } - return m_status == Status_Ok; + m_wallet->init(daemon_address, upper_transaction_size_limit); + if (Utils::isAddressLocal(daemon_address)) { + this->setTrustedDaemon(true); + } + bool result = this->refresh(); + // enabling background refresh thread + startRefresh(); + return result; + } +void WalletImpl::initAsync(const string &daemon_address, uint64_t upper_transaction_size_limit) +{ + clearStatus(); + m_wallet->init(daemon_address, upper_transaction_size_limit); + if (Utils::isAddressLocal(daemon_address)) { + this->setTrustedDaemon(true); + } + startRefresh(); +} + + + uint64_t WalletImpl::balance() const { return m_wallet->balance(); @@ -594,6 +608,11 @@ bool WalletImpl::connectToDaemon() return result; } +bool WalletImpl::connected() const +{ + return m_wallet->check_connection(); +} + void WalletImpl::setTrustedDaemon(bool arg) { m_trustedDaemon = arg; @@ -619,8 +638,13 @@ void WalletImpl::refreshThreadFunc() if (m_refreshThreadDone) { break; } + LOG_PRINT_L3(__FUNCTION__ << ": waiting for refresh..."); m_refreshCV.wait_for(lock, std::chrono::seconds(m_refreshIntervalSeconds)); + LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired..."); + LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled); + LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << m_status); if (m_refreshEnabled && m_status == Status_Ok) { + LOG_PRINT_L3(__FUNCTION__ << ": refreshing..."); doRefresh(); } } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index e9da0534..68ca364c 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -68,7 +68,9 @@ public: std::string filename() const; std::string keysFilename() const; bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit); + void initAsync(const std::string &daemon_address, uint64_t upper_transaction_size_limit); bool connectToDaemon(); + bool connected() const; void setTrustedDaemon(bool arg); bool trustedDaemon() const; uint64_t balance() const; diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index bf072ccc..ca83806f 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -137,6 +137,11 @@ WalletManager *WalletManagerFactory::getWalletManager() return g_walletManager; } +void WalletManagerFactory::setLogLevel(int level) +{ + epee::log_space::log_singletone::get_set_log_detalisation_level(true, level); +} + } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index f6c57367..2c583657 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -116,11 +116,10 @@ struct WalletListener virtual ~WalletListener() = 0; virtual void moneySpent(const std::string &txId, uint64_t amount) = 0; virtual void moneyReceived(const std::string &txId, uint64_t amount) = 0; - // generic callback, called when any event happened with the wallet; + // generic callback, called when any event (sent/received/block reveived/etc) happened with the wallet; virtual void updated() = 0; - // called when wallet refreshed by background thread or explicitly + // called when wallet refreshed by background thread or explicitly called be calling "refresh" synchronously virtual void refreshed() = 0; - }; @@ -175,9 +174,38 @@ struct Wallet * \return */ virtual std::string keysFilename() const = 0; - + /*! + * \brief init - initializes wallet with daemon connection params. implicitly connects to the daemon + * and refreshes the wallet. "refreshed" callback will be invoked. if daemon_address is + * local address, "trusted daemon" will be set to true forcibly + * + * \param daemon_address - daemon address in "hostname:port" format + * \param upper_transaction_size_limit + * \return - true if initialized and refreshed successfully + */ virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; + + /*! + * \brief init - initalizes wallet asynchronously. logic is the same as "init" but returns immediately. + * "refreshed" callback will be invoked. + * + * \param daemon_address - daemon address in "hostname:port" format + * \param upper_transaction_size_limit + * \return - true if initialized and refreshed successfully + */ + virtual void initAsync(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; + + /** + * @brief connectToDaemon - connects to the daemon. TODO: check if it can be removed + * @return + */ virtual bool connectToDaemon() = 0; + + /** + * @brief connected - checks if the wallet connected to the daemon + * @return - true if connected + */ + virtual bool connected() const = 0; virtual void setTrustedDaemon(bool arg) = 0; virtual bool trustedDaemon() const = 0; virtual uint64_t balance() const = 0; @@ -296,8 +324,22 @@ struct WalletManager struct WalletManagerFactory { + // logging levels for underlying library + enum LogLevel { + LogLevel_Silent = -1, + LogLevel_0 = 0, + LogLevel_1 = 1, + LogLevel_2 = 2, + LogLevel_3 = 3, + LogLevel_4 = 4, + LogLevel_Min = LogLevel_Silent, + LogLevel_Max = LogLevel_4 + }; + static WalletManager * getWalletManager(); + static void setLogLevel(int level); }; + } diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 51f59def..d642534b 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -31,6 +31,7 @@ #include "gtest/gtest.h" #include "wallet/wallet2_api.h" +#include "include_base_utils.h" #include #include @@ -73,7 +74,7 @@ const std::string TESTNET_WALLET6_NAME = WALLETS_ROOT_DIR + "wallet_06.bin"; const char * TESTNET_WALLET_PASS = ""; -const std::string CURRENT_SRC_WALLET = TESTNET_WALLET3_NAME; +const std::string CURRENT_SRC_WALLET = TESTNET_WALLET1_NAME; const std::string CURRENT_DST_WALLET = TESTNET_WALLET6_NAME; const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; @@ -139,6 +140,7 @@ struct WalletManagerTest : public testing::Test { std::cout << __FUNCTION__ << std::endl; wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + // Bitmonero::WalletManagerFactory::setLogLevel(Bitmonero::WalletManagerFactory::LogLevel_4); Utils::deleteWallet(WALLET_NAME); Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string()); } @@ -178,7 +180,6 @@ struct WalletTest2 : public testing::Test }; -/* TEST_F(WalletManagerTest, WalletManagerCreatesWallet) { @@ -246,7 +247,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword) ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2)); ASSERT_TRUE(wmgr->closeWallet(wallet1)); Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2); - ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);quint64 + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet2->seed() == seed1); ASSERT_TRUE(wmgr->closeWallet(wallet2)); Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); @@ -346,10 +347,10 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4) ASSERT_TRUE(wallet1->address() == address1); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -*/ -/* + + TEST_F(WalletManagerTest, WalletManagerFindsWallet) { std::vector wallets = wmgr->findWallets(WALLETS_ROOT_DIR); @@ -633,7 +634,7 @@ TEST_F(WalletTest1, WalletTransactionWithPaymentId) ASSERT_TRUE(payment_id_in_history); } -*/ + struct MyWalletListener : public Bitmonero::WalletListener { @@ -642,21 +643,38 @@ struct MyWalletListener : public Bitmonero::WalletListener uint64_t total_tx; uint64_t total_rx; std::mutex mutex; - std::condition_variable cv; + std::condition_variable cv_send; + std::condition_variable cv_receive; + std::condition_variable cv_update; + std::condition_variable cv_refresh; + bool send_triggered; + bool receive_triggered; + bool update_triggered; + bool refresh_triggered; + + MyWalletListener(Bitmonero::Wallet * wallet) : total_tx(0), total_rx(0) { + reset(); + this->wallet = wallet; this->wallet->setListener(this); } + void reset() + { + send_triggered = receive_triggered = update_triggered = refresh_triggered = false; + } + virtual void moneySpent(const string &txId, uint64_t amount) { std::cerr << "wallet: " << wallet->address() << "**** just spent money (" << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; total_tx += amount; - cv.notify_one(); + send_triggered = true; + cv_send.notify_one(); } virtual void moneyReceived(const string &txId, uint64_t amount) @@ -664,22 +682,62 @@ struct MyWalletListener : public Bitmonero::WalletListener std::cout << "wallet: " << wallet->address() << "**** just received money (" << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; total_rx += amount; - cv.notify_one(); + receive_triggered = true; + cv_receive.notify_one(); } virtual void updated() { - cv.notify_one(); + std::cout << __FUNCTION__ << "Wallet updated"; + update_triggered = true; + cv_update.notify_one(); } virtual void refreshed() { - std::cout << "Wallet refreshed"; + std::cout << __FUNCTION__ << "Wallet refreshed"; + refresh_triggered = true; + cv_refresh.notify_one(); } }; +TEST_F(WalletTest2, WalletCallBackRefreshedSync) +{ + + Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src); + ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_src_listener->refresh_triggered); + ASSERT_TRUE(wallet_src->connected()); +// std::chrono::seconds wait_for = std::chrono::seconds(60*3); +// std::unique_lock lock (wallet_src_listener->mutex); +// wallet_src_listener->cv_refresh.wait_for(lock, wait_for); + wmgr->closeWallet(wallet_src); +} + + +TEST_F(WalletTest2, WalletCallBackRefreshedAsync) +{ + + Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src); + + std::chrono::seconds wait_for = std::chrono::seconds(20); + std::unique_lock lock (wallet_src_listener->mutex); + wallet_src->initAsync(TESTNET_DAEMON_ADDRESS, 0); + std::cerr << "TEST: waiting on refresh lock...\n"; + wallet_src_listener->cv_refresh.wait_for(lock, wait_for); + std::cerr << "TEST: refresh lock acquired...\n"; + ASSERT_TRUE(wallet_src_listener->refresh_triggered); + ASSERT_TRUE(wallet_src->connected()); + std::cerr << "TEST: closing wallet...\n"; + wmgr->closeWallet(wallet_src); +} + + + TEST_F(WalletTest2, WalletCallbackSent) { @@ -707,7 +765,11 @@ TEST_F(WalletTest2, WalletCallbackSent) std::chrono::seconds wait_for = std::chrono::seconds(60*3); std::unique_lock lock (wallet_src_listener->mutex); - wallet_src_listener->cv.wait_for(lock, wait_for); + std::cerr << "TEST: waiting on send lock...\n"; + wallet_src_listener->cv_send.wait_for(lock, wait_for); + std::cerr << "TEST: send lock acquired...\n"; + ASSERT_TRUE(wallet_src_listener->send_triggered); + ASSERT_TRUE(wallet_src_listener->update_triggered); std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; ASSERT_TRUE(wallet_src->balance() < balance); wmgr->closeWallet(wallet_src); @@ -730,7 +792,6 @@ TEST_F(WalletTest2, WalletCallbackReceived) uint64_t balance = wallet_dst->balance(); MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst); - uint64_t amount = AMOUNT_1XMR * 5; std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address(); Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet_dst->address(), @@ -745,7 +806,11 @@ TEST_F(WalletTest2, WalletCallbackReceived) std::chrono::seconds wait_for = std::chrono::seconds(60*4); std::unique_lock lock (wallet_dst_listener->mutex); - wallet_dst_listener->cv.wait_for(lock, wait_for); + std::cerr << "TEST: waiting on receive lock...\n"; + wallet_dst_listener->cv_receive.wait_for(lock, wait_for); + std::cerr << "TEST: receive lock acquired...\n"; + ASSERT_TRUE(wallet_dst_listener->receive_triggered); + ASSERT_TRUE(wallet_dst_listener->update_triggered); std::cout << "** Balance: " << wallet_dst->displayAmount(wallet_src->balance()) << std::endl; ASSERT_TRUE(wallet_dst->balance() > balance); @@ -754,13 +819,9 @@ TEST_F(WalletTest2, WalletCallbackReceived) } - - - - int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); }