From 00ed12bd6c6457749e018b93301ec18c1a0624ab Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 24 Jun 2016 16:17:06 +0300 Subject: [PATCH 1/8] Wallet::paymentIdValid --- src/wallet/api/wallet.cpp | 6 ++++++ src/wallet/wallet2_api.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index be379cb99..5a0642f30 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -144,6 +144,12 @@ std::string Wallet::genPaymentId() } +bool Wallet::paymentIdValid(const string &paiment_id) +{ + crypto::hash8 pid; + return tools::wallet2::parse_short_payment_id(paiment_id, pid); +} + ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 66987e4c5..fefdf98c4 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -175,6 +175,7 @@ struct Wallet static uint64_t amountFromString(const std::string &amount); static uint64_t amountFromDouble(double amount); static std::string genPaymentId(); + static bool paymentIdValid(const std::string &paiment_id); // TODO? // virtual uint64_t unlockedDustBalance() const = 0; From 083380cb8f121190746195c45e6766f543b87d0f Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 27 Jun 2016 14:55:13 +0300 Subject: [PATCH 2/8] Transaction fee multiplier aka priority integraged --- src/wallet/api/wallet.cpp | 8 ++++-- src/wallet/api/wallet.h | 5 +++- src/wallet/wallet2_api.h | 16 +++++++++++- tests/libwallet_api_tests/main.cpp | 42 ++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5a0642f30..3f2ea50bd 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -402,7 +402,9 @@ bool WalletImpl::refresh() // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count) +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count, + PendingTransaction::Priority priority) + { clearStatus(); vector dsts; @@ -464,8 +466,10 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const //std::vector ptx_vector; try { + // priority called "fee_multiplied in terms of underlying wallet interface transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, - 0 /* unused fee arg*/, extra, m_trustedDaemon); + static_cast(priority), + extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 164aede1a..0896f51ee 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -71,8 +71,11 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); + PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, - uint64_t amount, uint32_t mixin_count); + uint64_t amount, uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low); + virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index fefdf98c4..fb3f9a648 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -50,6 +50,14 @@ struct PendingTransaction Status_Ok, Status_Error }; + + enum Priority { + Priority_Low = 1, + Priority_Medium = 2, + Priority_High = 3, + Priority_Last + }; + virtual ~PendingTransaction() = 0; virtual int status() const = 0; virtual std::string errorString() const = 0; @@ -186,13 +194,19 @@ struct Wallet * \param payment_id optional payment_id, can be empty string * \param amount amount * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \param priority * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() * after object returned */ virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, - uint64_t amount, uint32_t mixin_count) = 0; + uint64_t amount, uint32_t mixin_count, + PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0; + /*! + * \brief disposeTransaction - destroys transaction object + * \param t - pointer to the "PendingTransaction" object. Pointer is not valid after function returned; + */ virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index f6f1b0832..df06d68ae 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -482,6 +482,48 @@ TEST_F(WalletTest1, WalletTransactionWithMixin) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } +TEST_F(WalletTest1, WalletTransactionWithPriority) +{ + + std::string payment_id = ""; + + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + + // make sure testnet daemon is running + ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet1->refresh()); + uint64_t balance = wallet1->balance(); + ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok); + + std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + uint32_t mixin = 2; + uint64_t fee = 0; + + std::vector priorities = { + Bitmonero::PendingTransaction::Priority_Low, + Bitmonero::PendingTransaction::Priority_Medium, + Bitmonero::PendingTransaction::Priority_High + }; + + for (auto it = priorities.begin(); it != priorities.end(); ++it) { + std::cerr << "Transaction priority: " << *it << std::endl; + Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( + recepient_address, payment_id, AMOUNT_5XMR, mixin, *it); + std::cerr << "Transaction status: " << transaction->status() << std::endl; + std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl; + std::cerr << "Transaction error: " << transaction->errorString() << std::endl; + ASSERT_TRUE(transaction->fee() > fee); + ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); + fee = transaction->fee(); + wallet1->disposeTransaction(transaction); + } + wallet1->refresh(); + ASSERT_TRUE(wallet1->balance() == balance); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} + + + TEST_F(WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); From d27b883b2dab1ad235e3a4dc9c8c9230c5042d95 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 4 Jul 2016 17:59:53 +0300 Subject: [PATCH 3/8] hack to successfull linking for MSYS2 --- src/wallet/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 0b8fe4cb1..7ed1004e2 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -76,11 +76,15 @@ target_link_libraries(wallet ${EXTRA_LIBRARIES}) -set(libs_to_merge wallet cryptonote_core mnemonics common crypto) +# set(libs_to_merge wallet cryptonote_core mnemonics common crypto ${UNBOUND_LIBRARY} ) +set(libs_to_merge wallet cryptonote_core mnemonics common crypto) #MERGE_STATIC_LIBS(wallet_merged wallet_merged "${libs_to_merge}") merge_static_libs(wallet_merged "${libs_to_merge}") -install(TARGETS wallet_merged +# hack - repack libunbound into another static lib - there's conflicting object file "random.c.obj" +merge_static_libs(wallet_merged2 "${UNBOUND_LIBRARY}") + +install(TARGETS wallet_merged wallet_merged2 ARCHIVE DESTINATION lib) install(FILES ${wallet_api_headers} From 9d2cb4f36ca7220bb05217547b72710b870f6e57 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Sun, 10 Jul 2016 17:17:23 +0300 Subject: [PATCH 4/8] WalletListener functionality --- src/wallet/api/wallet.cpp | 89 +++++++++++++-- src/wallet/api/wallet.h | 21 +++- src/wallet/wallet2_api.h | 8 +- tests/libwallet_api_tests/main.cpp | 107 ++++++++++++------ .../libwallet_api_tests/scripts/send_funds.sh | 24 +++- 5 files changed, 196 insertions(+), 53 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 3f2ea50bd..f71cbd85b 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -46,6 +46,7 @@ namespace Bitmonero { namespace { // copy-pasted from simplewallet static const size_t DEFAULT_MIXIN = 4; + static const int DEFAULT_REFRESH_INTERVAL_SECONDS = 10; } struct Wallet2CallbackImpl : public tools::i_wallet2_callback @@ -75,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_L3(__FUNCTION__ << ": new block. height: " << height); + LOG_PRINT_L0(__FUNCTION__ << ": new block. height: " << height); } virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) @@ -84,11 +85,12 @@ 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_L3(__FUNCTION__ << ": money received. height: " << height + LOG_PRINT_L0(__FUNCTION__ << ": money received. height: " << height << ", tx: " << tx_hash << ", amount: " << print_money(amount)); if (m_listener) { m_listener->moneyReceived(tx_hash, amount); + m_listener->updated(); } } @@ -98,11 +100,12 @@ 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_L3(__FUNCTION__ << ": money spent. height: " << height + LOG_PRINT_L0(__FUNCTION__ << ": money spent. height: " << height << ", tx: " << tx_hash << ", amount: " << print_money(amount)); if (m_listener) { m_listener->moneySpent(tx_hash, amount); + m_listener->updated(); } } @@ -159,13 +162,22 @@ WalletImpl::WalletImpl(bool testnet) m_wallet = new tools::wallet2(testnet); m_history = new TransactionHistoryImpl(this); m_wallet2Callback = new Wallet2CallbackImpl; + m_wallet->callback(m_wallet2Callback); + m_refreshThreadDone = false; + m_refreshEnabled = false; + m_refreshIntervalSeconds = DEFAULT_REFRESH_INTERVAL_SECONDS; + m_refreshThread = std::thread([this] () { + this->refreshThreadFunc(); + }); + } WalletImpl::~WalletImpl() { - delete m_wallet2Callback; + stopRefresh(); delete m_history; delete m_wallet; + delete m_wallet2Callback; } bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language) @@ -359,6 +371,7 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact if (Utils::isAddressLocal(daemon_address)) { this->setTrustedDaemon(true); } + startRefresh(); } catch (const std::exception &e) { LOG_ERROR("Error initializing wallet: " << e.what()); @@ -383,15 +396,17 @@ uint64_t WalletImpl::unlockedBalance() const bool WalletImpl::refresh() { clearStatus(); - try { - m_wallet->refresh(); - } catch (const std::exception &e) { - m_status = Status_Error; - m_errorString = e.what(); - } + doRefresh(); return m_status == Status_Ok; } +void WalletImpl::refreshAsync() +{ + LOG_PRINT_L3(__FUNCTION__ << ": Refreshing asyncronously.."); + clearStatus(); + m_refreshCV.notify_one(); +} + // TODO: // 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) // 2 - check / design how "Transaction" can be single interface @@ -574,6 +589,8 @@ bool WalletImpl::connectToDaemon() m_status = result ? Status_Ok : Status_Error; if (!result) { m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address(); + } else { + // start refreshing here } return result; } @@ -594,5 +611,57 @@ void WalletImpl::clearStatus() m_errorString.clear(); } +void WalletImpl::refreshThreadFunc() +{ + LOG_PRINT_L3(__FUNCTION__ << ": starting refresh thread"); + + while (true) { + std::unique_lock lock(m_refreshMutex); + if (m_refreshThreadDone) { + break; + } + m_refreshCV.wait_for(lock, std::chrono::seconds(m_refreshIntervalSeconds)); + if (m_refreshEnabled && m_status == Status_Ok) { + doRefresh(); + } + } + LOG_PRINT_L3(__FUNCTION__ << ": refresh thread stopped"); +} + +void WalletImpl::doRefresh() +{ + // synchronizing async and sync refresh calls + std::lock_guard guarg(m_refreshMutex2); + try { + m_wallet->refresh(); + if (m_walletListener) { + m_walletListener->refreshed(); + } + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } +} + +// supposed to be called from ctor only +void WalletImpl::startRefresh() +{ + if (!m_refreshEnabled) { + m_refreshEnabled = true; + m_refreshCV.notify_one(); + } +} + + +// supposed to be called from dtor only +void WalletImpl::stopRefresh() +{ + if (!m_refreshThreadDone) { + m_refreshEnabled = false; + m_refreshThreadDone = true; + m_refreshThread.join(); + } +} + } // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 0896f51ee..e9da05347 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -35,6 +35,9 @@ #include "wallet/wallet2.h" #include +#include +#include +#include namespace Bitmonero { @@ -71,7 +74,7 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); - + void refreshAsync(); PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, uint64_t amount, uint32_t mixin_count, PendingTransaction::Priority priority = PendingTransaction::Priority_Low); @@ -84,19 +87,33 @@ public: private: void clearStatus(); + void refreshThreadFunc(); + void doRefresh(); + void startRefresh(); + void stopRefresh(); private: friend class PendingTransactionImpl; friend class TransactionHistoryImpl; tools::wallet2 * m_wallet; - int m_status; + std::atomic m_status; std::string m_errorString; std::string m_password; TransactionHistoryImpl * m_history; bool m_trustedDaemon; WalletListener * m_walletListener; Wallet2CallbackImpl * m_wallet2Callback; + + // multi-threaded refresh stuff + std::atomic m_refreshEnabled; + std::atomic m_refreshThreadDone; + std::atomic m_refreshIntervalSeconds; + std::mutex m_refreshMutex; + std::mutex m_refreshMutex2; + std::condition_variable m_refreshCV; + std::thread m_refreshThread; + }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index fb3f9a648..a51d38a71 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -116,7 +116,11 @@ 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; - // TODO: on_skip_transaction; + // generic callback, called when any event happened with the wallet; + virtual void updated() = 0; + // called when wallet refreshed by background thread or explicitly + virtual void refreshed() = 0; + }; @@ -188,6 +192,8 @@ struct Wallet // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; + + virtual void refreshAsync() = 0; /*! * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored * \param dst_addr destination address as string diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index df06d68ae..51f59def5 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include using namespace std; @@ -71,7 +73,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_WALLET1_NAME; +const std::string CURRENT_SRC_WALLET = TESTNET_WALLET3_NAME; const std::string CURRENT_DST_WALLET = TESTNET_WALLET6_NAME; const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; @@ -176,6 +178,7 @@ struct WalletTest2 : public testing::Test }; +/* TEST_F(WalletManagerTest, WalletManagerCreatesWallet) { @@ -235,7 +238,7 @@ TEST_F(WalletManagerTest, WalletManagerMovesWallet) } -/* + TEST_F(WalletManagerTest, WalletManagerChangesPassword) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -345,6 +348,8 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4) } */ + +/* TEST_F(WalletManagerTest, WalletManagerFindsWallet) { std::vector wallets = wmgr->findWallets(WALLETS_ROOT_DIR); @@ -415,7 +420,7 @@ TEST_F(WalletTest1, WalletConvertsToString) } -/* + TEST_F(WalletTest1, WalletTransaction) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -429,8 +434,10 @@ TEST_F(WalletTest1, WalletTransaction) wallet1->setDefaultMixin(1); ASSERT_TRUE(wallet1->defaultMixin() == 1); - Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( - recepient_address, AMOUNT_10XMR); + Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(recepient_address, + PAYMENT_ID_EMPTY, + AMOUNT_10XMR, + 1); ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); wallet1->refresh(); @@ -440,7 +447,6 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_FALSE(wallet1->balance() == balance); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -*/ TEST_F(WalletTest1, WalletTransactionWithMixin) { @@ -564,7 +570,7 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, PAYMENT_ID_EMPTY, - AMOUNT_10XMR * 5, 0); + AMOUNT_10XMR * 5, 1); ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); @@ -627,6 +633,7 @@ TEST_F(WalletTest1, WalletTransactionWithPaymentId) ASSERT_TRUE(payment_id_in_history); } +*/ struct MyWalletListener : public Bitmonero::WalletListener { @@ -634,7 +641,8 @@ struct MyWalletListener : public Bitmonero::WalletListener Bitmonero::Wallet * wallet; uint64_t total_tx; uint64_t total_rx; - std::timed_mutex guard; + std::mutex mutex; + std::condition_variable cv; MyWalletListener(Bitmonero::Wallet * wallet) : total_tx(0), total_rx(0) @@ -645,79 +653,110 @@ struct MyWalletListener : public Bitmonero::WalletListener virtual void moneySpent(const string &txId, uint64_t amount) { - std::cout << "wallet: " << wallet->address() << " just spent money (" + std::cerr << "wallet: " << wallet->address() << "**** just spent money (" << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; total_tx += amount; - guard.unlock(); + cv.notify_one(); } virtual void moneyReceived(const string &txId, uint64_t amount) { - std::cout << "wallet: " << wallet->address() << " just received money (" + std::cout << "wallet: " << wallet->address() << "**** just received money (" << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; total_rx += amount; - guard.unlock(); + cv.notify_one(); } + + virtual void updated() + { + cv.notify_one(); + } + + virtual void refreshed() + { + std::cout << "Wallet refreshed"; + } + }; -/* + TEST_F(WalletTest2, WalletCallbackSent) { - Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet_src->refresh()); MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src); + uint64_t balance = wallet_src->balance(); std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; + Bitmonero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, true); + + uint64_t amount = AMOUNT_1XMR * 5; + std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address(); - uint64_t amount = AMOUNT_10XMR * 5; - std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS; - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5); + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet_dst->address(), + PAYMENT_ID_EMPTY, + amount, 1); + std::cout << "** Committing transaction: " << Bitmonero::Wallet::displayAmount(tx->amount()) + << " with fee: " << Bitmonero::Wallet::displayAmount(tx->fee()); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); std::chrono::seconds wait_for = std::chrono::seconds(60*3); - - wallet_src_listener->guard.lock(); - wallet_src_listener->guard.try_lock_for(wait_for); - - ASSERT_TRUE(wallet_src_listener->total_tx != 0); + std::unique_lock lock (wallet_src_listener->mutex); + wallet_src_listener->cv.wait_for(lock, wait_for); + std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; + ASSERT_TRUE(wallet_src->balance() < balance); + wmgr->closeWallet(wallet_src); + wmgr->closeWallet(wallet_dst); } -*/ -/* + TEST_F(WalletTest2, WalletCallbackReceived) { - Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET5_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet_src->refresh()); std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; - Bitmonero::Wallet * wallet_dst = wmgr->openWallet(TESTNET_WALLET4_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, true); ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet_dst->refresh()); + 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 " << TESTNET_WALLET4_ADDRESS; - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5); + std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address(); + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet_dst->address(), + PAYMENT_ID_EMPTY, + amount, 1); + + std::cout << "** Committing transaction: " << Bitmonero::Wallet::displayAmount(tx->amount()) + << " with fee: " << Bitmonero::Wallet::displayAmount(tx->fee()); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); 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::cout << "** Balance: " << wallet_dst->displayAmount(wallet_src->balance()) << std::endl; + ASSERT_TRUE(wallet_dst->balance() > balance); - wallet_dst_listener->guard.lock(); - wallet_dst_listener->guard.try_lock_for(wait_for); - - ASSERT_TRUE(wallet_dst_listener->total_tx != 0); - + wmgr->closeWallet(wallet_src); + wmgr->closeWallet(wallet_dst); } -*/ + + + + + int main(int argc, char** argv) { diff --git a/tests/libwallet_api_tests/scripts/send_funds.sh b/tests/libwallet_api_tests/scripts/send_funds.sh index 306b06a40..437e4f240 100755 --- a/tests/libwallet_api_tests/scripts/send_funds.sh +++ b/tests/libwallet_api_tests/scripts/send_funds.sh @@ -12,11 +12,23 @@ function send_funds { } -send_funds 100 wallet_01.bin -send_funds 100 wallet_02.bin -send_funds 100 wallet_03.bin -send_funds 100 wallet_04.bin -send_funds 100 wallet_05.bin -send_funds 100 wallet_06.bin +function seed_wallets { + local amount=$1 + send_funds $amount wallet_01.bin + send_funds $amount wallet_02.bin + send_funds $amount wallet_03.bin + send_funds $amount wallet_04.bin + send_funds $amount wallet_05.bin + send_funds $amount wallet_06.bin +} + +seed_wallets 1 +seed_wallets 2 +seed_wallets 5 +seed_wallets 10 +seed_wallets 20 +seed_wallets 50 +seed_wallets 100 + From 10c06ddac72559eb986868e69ae7f4861c48cd15 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 13 Jul 2016 13:13:10 +0300 Subject: [PATCH 5/8] wallet_api: segfault on refresh fixed --- src/wallet/api/wallet.cpp | 4 ++-- src/wallet/wallet2_api.h | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index f71cbd85b..15cffe2af 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -634,8 +634,8 @@ void WalletImpl::doRefresh() std::lock_guard guarg(m_refreshMutex2); try { m_wallet->refresh(); - if (m_walletListener) { - m_walletListener->refreshed(); + if (m_wallet2Callback->getListener()) { + m_wallet2Callback->getListener()->refreshed(); } } catch (const std::exception &e) { m_status = Status_Error; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index a51d38a71..f6c573673 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -189,10 +189,14 @@ struct Wallet static std::string genPaymentId(); static bool paymentIdValid(const std::string &paiment_id); - // TODO? - // virtual uint64_t unlockedDustBalance() const = 0; + /** + * @brief refresh - refreshes the wallet, updating transactions from daemon + * @return - true if refreshed successfully; + */ virtual bool refresh() = 0; - + /** + * @brief refreshAsync - refreshes wallet asynchronously. + */ virtual void refreshAsync() = 0; /*! * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored From 193d2513607edf316e283a7360501e1d1feab2a0 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 13 Jul 2016 15:26:31 +0300 Subject: [PATCH 6/8] libwallet_api cmake: conditionally creating libwallet_merged2 only for STATIC build --- src/wallet/CMakeLists.txt | 23 ++++++++++++++++------- src/wallet/api/wallet.cpp | 3 +-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 7ed1004e2..086758c39 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -75,17 +75,26 @@ target_link_libraries(wallet ${Boost_REGEX_LIBRARY} ${EXTRA_LIBRARIES}) + +# in case of static build, randon.c.obj from UNBOUND_LIBARY conflicts with the same file from 'crypto' +# and in case of dynamic build, merge_static_libs called with ${UNBOUND_LIBRARY} will fail +if (STATIC) + set(libs_to_merge wallet cryptonote_core mnemonics common crypto) + # hack - repack libunbound into another static lib - there's conflicting object file "random.c.obj" + merge_static_libs(wallet_merged "${libs_to_merge}") + merge_static_libs(wallet_merged2 "${UNBOUND_LIBRARY}") + install(TARGETS wallet_merged wallet_merged2 + ARCHIVE DESTINATION lib) +else (STATIC) + set(libs_to_merge wallet cryptonote_core mnemonics common crypto ${UNBOUND_LIBRARY} ) + merge_static_libs(wallet_merged "${libs_to_merge}") + install(TARGETS wallet_merged + ARCHIVE DESTINATION lib) +endif (STATIC) -# set(libs_to_merge wallet cryptonote_core mnemonics common crypto ${UNBOUND_LIBRARY} ) -set(libs_to_merge wallet cryptonote_core mnemonics common crypto) #MERGE_STATIC_LIBS(wallet_merged wallet_merged "${libs_to_merge}") -merge_static_libs(wallet_merged "${libs_to_merge}") -# hack - repack libunbound into another static lib - there's conflicting object file "random.c.obj" -merge_static_libs(wallet_merged2 "${UNBOUND_LIBRARY}") -install(TARGETS wallet_merged wallet_merged2 - ARCHIVE DESTINATION lib) install(FILES ${wallet_api_headers} DESTINATION include/wallet) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 15cffe2af..e75f5afdb 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -371,8 +371,7 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact if (Utils::isAddressLocal(daemon_address)) { this->setTrustedDaemon(true); } - startRefresh(); - + refresh(); } catch (const std::exception &e) { LOG_ERROR("Error initializing wallet: " << e.what()); m_status = Status_Error; From 6d32a3d16b8bb1bf2a51a41ce9f826cf31d02352 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Jul 2016 12:47:01 +0300 Subject: [PATCH 7/8] 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 e75f5afdb..2322cac76 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 e9da05347..68ca364cf 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 bf072ccca..ca83806ff 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 f6c573673..2c5836573 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 51f59def5..d642534b0 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(); } From d7597c5961ed1e8be8a7eca8c52e491b500797c6 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 14 Jul 2016 13:33:49 +0300 Subject: [PATCH 8/8] refreshing wallet even if error happened --- src/wallet/api/wallet.cpp | 20 ++++++++++++++------ src/wallet/api/wallet.h | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 2322cac76..67d2ebecb 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -643,7 +643,7 @@ void WalletImpl::refreshThreadFunc() 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) { + if (m_refreshEnabled /*&& m_status == Status_Ok*/) { LOG_PRINT_L3(__FUNCTION__ << ": refreshing..."); doRefresh(); } @@ -657,16 +657,16 @@ void WalletImpl::doRefresh() std::lock_guard guarg(m_refreshMutex2); try { m_wallet->refresh(); - if (m_wallet2Callback->getListener()) { - m_wallet2Callback->getListener()->refreshed(); - } } catch (const std::exception &e) { m_status = Status_Error; m_errorString = e.what(); } + if (m_wallet2Callback->getListener()) { + m_wallet2Callback->getListener()->refreshed(); + } } -// supposed to be called from ctor only + void WalletImpl::startRefresh() { if (!m_refreshEnabled) { @@ -676,7 +676,7 @@ void WalletImpl::startRefresh() } -// supposed to be called from dtor only + void WalletImpl::stopRefresh() { if (!m_refreshThreadDone) { @@ -686,5 +686,13 @@ void WalletImpl::stopRefresh() } } +void WalletImpl::pauseRefresh() +{ + // TODO synchronize access + if (!m_refreshThreadDone) { + m_refreshEnabled = false; + } +} + } // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 68ca364cf..9a290e0bc 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -93,6 +93,7 @@ private: void doRefresh(); void startRefresh(); void stopRefresh(); + void pauseRefresh(); private: friend class PendingTransactionImpl; @@ -111,7 +112,10 @@ private: std::atomic m_refreshEnabled; std::atomic m_refreshThreadDone; std::atomic m_refreshIntervalSeconds; + // synchronizing refresh loop; std::mutex m_refreshMutex; + + // synchronizing sync and async refresh std::mutex m_refreshMutex2; std::condition_variable m_refreshCV; std::thread m_refreshThread;