From c111b0acd7231e458092f6d5527064c4f78276ba Mon Sep 17 00:00:00 2001 From: woodser Date: Sun, 11 Aug 2019 09:47:09 -0400 Subject: [PATCH] sample code completing successfully; implement wait_for_next_block() without returning height; fix query make_shared copy --- src/wallet/monero_wallet.cpp | 48 +++++++++++++++++++++++++++++++----- src/wallet/monero_wallet.h | 7 ++++++ test/sample_code.cpp | 22 +++++++++++------ todo.txt | 7 ++++-- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/wallet/monero_wallet.cpp b/src/wallet/monero_wallet.cpp index ef884ac..f44af35 100644 --- a/src/wallet/monero_wallet.cpp +++ b/src/wallet/monero_wallet.cpp @@ -1481,15 +1481,17 @@ namespace monero { // copy and normalize query shared_ptr _query; - if (query.m_tx_query == boost::none) _query = query.copy(make_shared(query), make_shared()); - else { + if (query.m_tx_query == boost::none) { + shared_ptr query_ptr = make_shared(query); // convert to shared pointer for copy // TODO: does this copy unecessarily? copy constructor is not defined + _query = query_ptr->copy(query_ptr, make_shared()); + } else { shared_ptr tx_query = query.m_tx_query.get()->copy(query.m_tx_query.get(), make_shared()); if (query.m_tx_query.get()->m_transfer_query != boost::none && query.m_tx_query.get()->m_transfer_query.get().get() == &query) { _query = tx_query->m_transfer_query.get(); } else { if (query.m_tx_query.get()->m_transfer_query != boost::none) throw new runtime_error("Transfer query's tx query must be a circular reference or null"); - shared_ptr querySp = make_shared(query); // convert query to shared pointer for copy - _query = querySp->copy(querySp, make_shared()); + shared_ptr query_ptr = make_shared(query); // convert query to shared pointer for copy + _query = query_ptr->copy(query_ptr, make_shared()); _query->m_tx_query = tx_query; } } @@ -1617,8 +1619,10 @@ namespace monero { // copy and normalize query shared_ptr _query; - if (query.m_tx_query == boost::none) _query = query.copy(make_shared(query), make_shared()); - else { + if (query.m_tx_query == boost::none) { + shared_ptr query_ptr = make_shared(query); // convert to shared pointer for copy + _query = query_ptr->copy(query_ptr, make_shared()); + } else { shared_ptr tx_query = query.m_tx_query.get()->copy(query.m_tx_query.get(), make_shared()); if (query.m_tx_query.get()->m_output_query != boost::none && query.m_tx_query.get()->m_output_query.get().get() == &query) { _query = tx_query->m_output_query.get(); @@ -2490,6 +2494,38 @@ namespace monero { m_w2->store(); } + uint64_t monero_wallet::wait_for_next_block() { + + // use mutex and condition variable to wait for block + boost::mutex temp; + boost::condition_variable cv; + + // create listener which notifies condition variable when block is added + struct block_notifier : monero_wallet_listener { + boost::mutex* temp; + boost::condition_variable* cv; + block_notifier(boost::mutex* temp, boost::condition_variable* cv) { this->temp = temp; this->cv = cv; } + void on_new_block(uint64_t height) { + cout << "ON NEW BLOCK!!!! " << height << endl; + //boost::lock_guard guarg(*temp); + cv->notify_one(); + } + } block_listener(&temp, &cv); + + // register the listener + add_listener(block_listener); + + // wait until condition variable is notified + boost::mutex::scoped_lock lock(temp); + cv.wait(lock); + + // unregister the listener + remove_listener(block_listener); + + // return notified height + return 0; // TODO + } + void monero_wallet::move_to(string path, string password) { MTRACE("move_to(" << path << ", " << password << ")"); m_w2->store_to(path, password); diff --git a/src/wallet/monero_wallet.h b/src/wallet/monero_wallet.h index 365629d..34dde9e 100644 --- a/src/wallet/monero_wallet.h +++ b/src/wallet/monero_wallet.h @@ -1276,6 +1276,13 @@ namespace monero { */ void stop_mining(); + /** + * Wait for the next block to be added to the chain. + * + * @return the height of the next block when it is added to the chain + */ + uint64_t wait_for_next_block(); + /** * Save the wallet at its current path. */ diff --git a/test/sample_code.cpp b/test/sample_code.cpp index 297ad7d..45e01e0 100644 --- a/test/sample_code.cpp +++ b/test/sample_code.cpp @@ -5,6 +5,8 @@ using namespace std; +bool OUTPUT_RECEIVED = false; + /** * This code introduces the API. * @@ -13,6 +15,10 @@ using namespace std; */ int main(int argc, const char* argv[]) { +// // configure logging +// mlog_configure("log_cpp_sample_code.txt", true); +// mlog_set_log_level(1); + // create a wallet from a mnemonic phrase string mnemonic = "hefty value later extra artistic firm radar yodel talent future fungal nutshell because sanity awesome nail unjustly rage unafraid cedar delayed thumbs comb custom sanity"; monero_wallet* wallet_restored = monero_wallet::create_wallet_from_mnemonic( @@ -43,7 +49,7 @@ int main(int argc, const char* argv[]) { // query a transaction by id monero_tx_query tx_query; - tx_query.m_id = "3276252c5a545b90c8e147fcde45d3e1917726470a8f7d4c8977b527a44dfd15"; + tx_query.m_id = "314a0f1375db31cea4dac4e0a51514a6282b43792269b3660166d4d2b46437ca"; shared_ptr tx = wallet_restored->get_txs(tx_query)[0]; for (const shared_ptr in_transfer : tx->m_incoming_transfers) { uint64_t in_amount = in_transfer->m_amount.get(); @@ -71,6 +77,7 @@ int main(int argc, const char* argv[]) { ); // continuously synchronize the wallet + wallet_random->sync(); // TODO: is this necessary here to be synced? random wallet should be synced if created with rpc connection wallet_random->start_syncing(); // get wallet info @@ -83,9 +90,10 @@ int main(int argc, const char* argv[]) { struct : monero_wallet_listener { void on_output_received(const monero_output_wallet& output) { cout << "Wallet received funds!" << endl; + string tx_id = output.m_tx->m_id.get(); int account_index = output.m_account_index.get(); int subaddress_index = output.m_subaddress_index.get(); - shared_ptr key_image = output.m_key_image.get(); + OUTPUT_RECEIVED = true; } } my_listener; wallet_random->add_listener(my_listener); @@ -101,9 +109,7 @@ int main(int argc, const char* argv[]) { wallet_restored->start_mining(num_threads, is_background, ignore_battery); // wait for the next block to be added to the chain -// uint64_t next_height = wallet_random->wait_for_next_block(); -// MoneroBlockHeader nextBlockHeader = daemon.getNextBlockHeader(); -// long nextNumTxs = nextBlockHeader.getNumTxs(); + uint64_t next_height = wallet_random->wait_for_next_block(); // stop mining wallet_restored->stop_mining(); @@ -125,7 +131,7 @@ int main(int argc, const char* argv[]) { uint64_t fee = created_tx->m_fee.get(); // "Are you sure you want to send ...?" wallet_restored->relay_tx(*created_tx); // submit the transaction to the Monero network which will notify the recipient wallet - // random wallet will receive notification of incoming output after a moment - //TimeUnit.SECONDS.sleep(10); - //assertTrue(JNI_OUTPUT_RECEIVED); + // random wallet has received notification of incoming output + if (OUTPUT_RECEIVED) cout << "Sample code completed successfully" << endl; + else throw runtime_error("Output should have been received"); } diff --git a/todo.txt b/todo.txt index 0267b8d..0178c7e 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,13 @@ HIGH PRIORITY -ensure model toPropertyTrees(), etc are not unecessarily copying return objects +cv(cv) in constructor is short hand to invoke copy constructor gen documentation sample code including readme -monero_wallet_listener should be a class? MEDIUM PRIORITY +polish model: no boost::optional? no boost::optional? etc +ensure model toPropertyTrees(), etc are not unecessarily copying return objects +monero_wallet_listener should be a class? +way to use copy constructors instead of query copy(sp, sp) methods? separate wallet default impl from must impl create_tx and send_tx request arg should be const; need to copy should not need wallet.h / wallet.cpp as dependency, why are GUI deps needed?