diff options
-rw-r--r-- | CMakeLists.txt | 11 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | contrib/rlwrap/monerocommands_bitmonerod.txt | 35 | ||||
-rw-r--r-- | contrib/rlwrap/monerocommands_monero-wallet-cli.txt | 33 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 6 | ||||
-rw-r--r-- | src/common/command_line.cpp | 6 | ||||
-rw-r--r-- | src/common/command_line.h | 1 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 5 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.h | 9 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler.inl | 4 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 4 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 69 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 13 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 32 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 1 | ||||
-rw-r--r-- | src/wallet/wallet2_api.h | 57 | ||||
-rw-r--r-- | tests/libwallet_api_tests/main.cpp | 154 | ||||
-rw-r--r-- | tests/libwallet_api_tests/scripts/README.md | 24 | ||||
-rwxr-xr-x | tests/libwallet_api_tests/scripts/create_wallets.sh | 4 | ||||
-rwxr-xr-x | tests/libwallet_api_tests/scripts/send_funds.sh | 2 | ||||
-rw-r--r-- | utils/gpg_keys/luigi1111.asc | 30 |
21 files changed, 442 insertions, 64 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f15c73dc..0d82324a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,10 +65,10 @@ else() set(ARCH_ID "${ARCH}") endif() string(TOLOWER "${ARCH_ID}" ARM_ID) -string(SUBSTRING "${ARCH_ID}" 0 3 ARM_TEST) +string(SUBSTRING "${ARM_ID}" 0 3 ARM_TEST) if (ARM_TEST STREQUAL "arm") set(ARM 1) - string(SUBSTRING "${ARCH_ID}" 0 5 ARM_TEST) + string(SUBSTRING "${ARM_ID}" 0 5 ARM_TEST) if (ARM_TEST STREQUAL "armv6") set(ARM6 1) endif() @@ -77,7 +77,7 @@ if (ARM_TEST STREQUAL "arm") endif() endif() -if (ARCH_ID STREQUAL "aarch64") +if (ARM_ID STREQUAL "aarch64") set(ARM 1) set(ARM8 1) endif() @@ -512,11 +512,6 @@ else() if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled, so explicitly disable set(USE_LTO false) - # explicitly define stdlib for older versions of clang - if(CMAKE_C_COMPILER_VERSION VERSION_LESS 3.7) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++") - endif() endif() @@ -164,11 +164,7 @@ application. * Download and install the [MSYS2 installer](http://msys2.github.io), either the 64-bit or the 32-bit package, depending on your system. * Open the MSYS shell via the `MSYS2 Shell` shortcut -* Update the core packages in your MSYS2 install: - - update-core - -* Exit the MSYS shell using Alt+F4, then restart MSYS and update packages using pacman: +* Update packages using pacman: pacman -Syuu diff --git a/contrib/rlwrap/monerocommands_bitmonerod.txt b/contrib/rlwrap/monerocommands_bitmonerod.txt new file mode 100644 index 000000000..c14d28e71 --- /dev/null +++ b/contrib/rlwrap/monerocommands_bitmonerod.txt @@ -0,0 +1,35 @@ +ban +bans +diff +exit +fast_exit +flush_txpool +hard_fork_info +help +hide_hr +is_key_image_spent +limit +limit_down +limit_up +out_peers +output_histogram +print_bc +print_block +print_cn +print_height +print_pl +print_pool +print_pool_sh +print_status +print_tx +q +save +set_log +show_hr +start_mining +start_save_graph +status +stop_daemon +stop_mining +stop_save_graph +unban diff --git a/contrib/rlwrap/monerocommands_monero-wallet-cli.txt b/contrib/rlwrap/monerocommands_monero-wallet-cli.txt new file mode 100644 index 000000000..c5e4c0323 --- /dev/null +++ b/contrib/rlwrap/monerocommands_monero-wallet-cli.txt @@ -0,0 +1,33 @@ +address +balance +bc_height +check_tx_key +export_key_images +get_tx_key +get_tx_note +help +import_key_images +incoming_transfers +integrated_address +payments +refresh +rescan_bc +rescan_spent +save +save_bc +save_watch_only +seed +set +set_tx_note +show_transfers +sign +spendkey +start_mining +status +stop_mining +sweep_all +sweep_unmixable +transfer +transfer_original +verify +viewkey diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 8ad875fc8..acb7d2cf6 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1081,7 +1081,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) if (need_resize()) { - LOG_PRINT_L0("LMDB memory map needs resized, doing that now."); + LOG_PRINT_L0("LMDB memory map needs to be resized, doing that now."); do_resize(); } @@ -1132,7 +1132,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) if (!(mdb_flags & MDB_RDONLY)) { result = mdb_drop(txn, m_hf_starting_heights, 1); - if (result) + if (result && result != MDB_NOTFOUND) throw0(DB_ERROR(lmdb_error("Failed to drop m_hf_starting_heights: ", result).c_str())); } @@ -2500,7 +2500,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c // for batch mode, DB resize check is done at start of batch transaction if (! m_batch_active && need_resize()) { - LOG_PRINT_L0("LMDB memory map needs resized, doing that now."); + LOG_PRINT_L0("LMDB memory map needs to be resized, doing that now."); do_resize(); } } diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index fc096abe5..b3f488447 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -30,6 +30,7 @@ #include "command_line.h" #include "string_tools.h" +#include "cryptonote_config.h" namespace command_line { @@ -92,4 +93,9 @@ namespace command_line , "Show time-stats when processing blocks/txs and disk synchronization." , 0 }; + const command_line::arg_descriptor<size_t> arg_block_sync_size = { + "block-sync-size" + , "How many blocks to sync at once during chain synchronization." + , BLOCKS_SYNCHRONIZING_DEFAULT_COUNT + }; } diff --git a/src/common/command_line.h b/src/common/command_line.h index 731b8b0bb..0ea749168 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -216,4 +216,5 @@ namespace command_line extern const arg_descriptor<uint64_t> arg_prep_blocks_threads; extern const arg_descriptor<uint64_t> arg_db_auto_remove_logs; extern const arg_descriptor<uint64_t> arg_show_time_stats; + extern const arg_descriptor<size_t> arg_block_sync_size; } diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index c289f297b..4abf6a898 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -142,6 +142,7 @@ namespace cryptonote command_line::add_arg(desc, command_line::arg_db_sync_mode); command_line::add_arg(desc, command_line::arg_show_time_stats); command_line::add_arg(desc, command_line::arg_db_auto_remove_logs); + command_line::add_arg(desc, command_line::arg_block_sync_size); } //----------------------------------------------------------------------------------------------- bool core::handle_command_line(const boost::program_options::variables_map& vm) @@ -403,6 +404,10 @@ namespace cryptonote m_blockchain_storage.set_show_time_stats(show_time_stats); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); + block_sync_size = command_line::get_arg(vm, command_line::arg_block_sync_size); + if (block_sync_size == 0) + block_sync_size = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; + // load json & DNS checkpoints, and verify them // with respect to what blocks we already have CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints."); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index d16bd6553..97abf3271 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -611,6 +611,13 @@ namespace cryptonote */ bool are_key_images_spent(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const; + /** + * @brief get the number of blocks to sync in one go + * + * @return the number of blocks to sync in one go + */ + size_t get_block_sync_size() const { return block_sync_size; } + private: /** @@ -798,6 +805,8 @@ namespace cryptonote std::atomic_flag m_checkpoints_updating; //!< set if checkpoints are currently updating to avoid multiple threads attempting to update at once boost::interprocess::file_lock db_lock; //!< a lock object for a file lock in the db directory + + size_t block_sync_size; }; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index f16dad281..6dfc9fbc5 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -650,9 +650,9 @@ namespace cryptonote size_t count = 0; auto it = context.m_needed_objects.begin(); - size_t count_limit = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; + const size_t count_limit = m_core.get_block_sync_size(); _note_c("net/req-calc" , "Setting count_limit: " << count_limit); - while(it != context.m_needed_objects.end() && count < BLOCKS_SYNCHRONIZING_DEFAULT_COUNT) + while(it != context.m_needed_objects.end() && count < count_limit) { if( !(check_having_blocks && m_core.have_block(*it))) { diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 7260ecf8a..279a5fa41 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -662,7 +662,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), tr("Display private view key")); m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Display private spend key")); m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Display Electrum-style mnemonic seed")); - m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin <n> - set default mixin (default default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [1|2|3] - normal/elevated/priority fee")); + m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin <n> - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [1|2|3] - normal/elevated/priority fee")); m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs")); m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), tr("Get transaction key (r) for a given <txid>")); m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>")); @@ -2489,7 +2489,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % print_money(e.fee())); - fail_msg_writer() << tr("Failed to find a way to create transactions"); + fail_msg_writer() << tr("Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e) { diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 74552bc03..eefb49e95 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -46,7 +46,9 @@ namespace Bitmonero { namespace { // copy-pasted from simplewallet static const size_t DEFAULT_MIXIN = 4; - static const int DEFAULT_REFRESH_INTERVAL_SECONDS = 10; + static const int DEFAULT_REFRESH_INTERVAL_MILLIS = 1000 * 10; + // limit maximum refresh interval as one minute + static const int MAX_REFRESH_INTERVAL_MILLIS = 1000 * 60 * 1; } struct Wallet2CallbackImpl : public tools::i_wallet2_callback @@ -75,8 +77,12 @@ 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); + + if (m_listener) { + m_listener->newBlock(height); + // m_listener->updated(); + } } virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, uint64_t amount) @@ -169,7 +175,9 @@ WalletImpl::WalletImpl(bool testnet) m_wallet->callback(m_wallet2Callback); m_refreshThreadDone = false; m_refreshEnabled = false; - m_refreshIntervalSeconds = DEFAULT_REFRESH_INTERVAL_SECONDS; + + m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS; + m_refreshThread = boost::thread([this] () { this->refreshThreadFunc(); }); @@ -272,14 +280,15 @@ bool WalletImpl::close() { bool result = false; + LOG_PRINT_L3("closing wallet..."); try { // do not store wallet with invalid status if (status() == Status_Ok) m_wallet->store(); - // LOG_PRINT_L0("wallet::store done"); - // LOG_PRINT_L0("Calling wallet::stop..."); + LOG_PRINT_L3("wallet::store done"); + LOG_PRINT_L3("Calling wallet::stop..."); m_wallet->stop(); - // LOG_PRINT_L0("wallet::stop done"); + LOG_PRINT_L3("wallet::stop done"); result = true; clearStatus(); } catch (const std::exception &e) { @@ -410,6 +419,27 @@ uint64_t WalletImpl::unlockedBalance() const return m_wallet->unlocked_balance(); } +uint64_t WalletImpl::blockChainHeight() const +{ + return m_wallet->get_blockchain_current_height(); +} + +uint64_t WalletImpl::daemonBlockChainHeight() const +{ + std::string err; + uint64_t result = m_wallet->get_daemon_blockchain_height(err); + if (!err.empty()) { + LOG_ERROR(__FUNCTION__ << ": " << err); + result = 0; + m_errorString = err; + m_status = Status_Error; + + } else { + m_status = Status_Ok; + m_errorString = ""; + } + return result; +} bool WalletImpl::refresh() { @@ -425,6 +455,22 @@ void WalletImpl::refreshAsync() m_refreshCV.notify_one(); } +void WalletImpl::setAutoRefreshInterval(int millis) +{ + if (millis > MAX_REFRESH_INTERVAL_MILLIS) { + LOG_ERROR(__FUNCTION__<< ": invalid refresh interval " << millis + << " ms, maximum allowed is " << MAX_REFRESH_INTERVAL_MILLIS << " ms"); + m_refreshIntervalMillis = MAX_REFRESH_INTERVAL_MILLIS; + } else { + m_refreshIntervalMillis = millis; + } +} + +int WalletImpl::autoRefreshInterval() const +{ + return m_refreshIntervalMillis; +} + // TODO: // 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) // 2 - check / design how "Transaction" can be single interface @@ -637,7 +683,15 @@ void WalletImpl::refreshThreadFunc() break; } LOG_PRINT_L3(__FUNCTION__ << ": waiting for refresh..."); - m_refreshCV.wait(lock); + // if auto refresh enabled, we wait for the "m_refreshIntervalSeconds" interval. + // if not - we wait forever + if (m_refreshIntervalMillis > 0) { + boost::posix_time::milliseconds wait_for_ms(m_refreshIntervalMillis); + m_refreshCV.timed_wait(lock, wait_for_ms); + } else { + m_refreshCV.wait(lock); + } + LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired..."); LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled); LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << m_status); @@ -680,6 +734,7 @@ void WalletImpl::stopRefresh() if (!m_refreshThreadDone) { m_refreshEnabled = false; m_refreshThreadDone = true; + m_refreshCV.notify_one(); m_refreshThread.join(); } } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 658296c30..d97a8f3b3 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -75,8 +75,15 @@ public: bool trustedDaemon() const; uint64_t balance() const; uint64_t unlockedBalance() const; + uint64_t blockChainHeight() const; + uint64_t daemonBlockChainHeight() const; bool refresh(); void refreshAsync(); + void setAutoRefreshInterval(int millis); + int autoRefreshInterval() const; + + + 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); @@ -100,8 +107,8 @@ private: friend class TransactionHistoryImpl; tools::wallet2 * m_wallet; - std::atomic<int> m_status; - std::string m_errorString; + mutable std::atomic<int> m_status; + mutable std::string m_errorString; std::string m_password; TransactionHistoryImpl * m_history; bool m_trustedDaemon; @@ -111,7 +118,7 @@ private: // multi-threaded refresh stuff std::atomic<bool> m_refreshEnabled; std::atomic<bool> m_refreshThreadDone; - std::atomic<int> m_refreshIntervalSeconds; + std::atomic<int> m_refreshIntervalMillis; // synchronizing refresh loop; boost::mutex m_refreshMutex; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3d4f93aff..ed4ab93de 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4053,6 +4053,38 @@ std::string wallet2::get_daemon_address() const return m_daemon_address; } +uint64_t wallet2::get_daemon_blockchain_height(string &err) +{ + // XXX: DRY violation. copy-pasted from simplewallet.cpp:get_daemon_blockchain_height() + // consider to move it from simplewallet to wallet2 ? + COMMAND_RPC_GET_HEIGHT::request req; + COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>(); + m_daemon_rpc_mutex.lock(); + bool ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); + m_daemon_rpc_mutex.unlock(); + // XXX: DRY violation. copy-pasted from simplewallet.cpp:interpret_rpc_response() + if (ok) + { + if (res.status == CORE_RPC_STATUS_BUSY) + { + err = "daemon is busy. Please try again later."; + } + else if (res.status != CORE_RPC_STATUS_OK) + { + err = res.status; + } + else // success, cleaning up error message + { + err = ""; + } + } + else + { + err = "possibly lost connection to daemon"; + } + return res.height; +} + void wallet2::set_tx_note(const crypto::hash &txid, const std::string ¬e) { m_tx_notes[txid] = note; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 89b613d34..dd7cd19dc 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -400,6 +400,7 @@ namespace tools std::string get_wallet_file() const; std::string get_keys_file() const; std::string get_daemon_address() const; + uint64_t get_daemon_blockchain_height(std::string& err); std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool trusted_daemon); std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index e880b1c68..08e2ae16b 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -114,11 +114,35 @@ struct TransactionHistory struct WalletListener { virtual ~WalletListener() = 0; + /** + * @brief moneySpent - called when money spent + * @param txId - transaction id + * @param amount - amount + */ virtual void moneySpent(const std::string &txId, uint64_t amount) = 0; + + /** + * @brief moneyReceived - called when money received + * @param txId - transaction id + * @param amount - amount + */ virtual void moneyReceived(const std::string &txId, uint64_t amount) = 0; - // generic callback, called when any event (sent/received/block reveived/etc) happened with the wallet; + + /** + * @brief newBlock - called when new block received + * @param height - block height + */ + virtual void newBlock(uint64_t height) = 0; + + /** + * @brief updated - 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 be calling "refresh" synchronously + + + /** + * @brief refreshed - called when wallet refreshed by background thread or explicitly refreshed by calling "refresh" synchronously + */ virtual void refreshed() = 0; }; @@ -211,6 +235,20 @@ struct Wallet virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; + /** + * @brief blockChainHeight - returns current blockchain height + * @return + */ + virtual uint64_t blockChainHeight() const = 0; + + /** + * @brief daemonBlockChainHeight - returns daemon blockchain height + * @return 0 - in case error communicating with the daemon. + * status() will return Status_Error and errorString() will return verbose error description + */ + virtual uint64_t daemonBlockChainHeight() const = 0; + + static std::string displayAmount(uint64_t amount); static uint64_t amountFromString(const std::string &amount); static uint64_t amountFromDouble(double amount); @@ -223,10 +261,25 @@ struct Wallet * @return - true if refreshed successfully; */ virtual bool refresh() = 0; + /** * @brief refreshAsync - refreshes wallet asynchronously. */ virtual void refreshAsync() = 0; + + /** + * @brief setAutoRefreshInterval - setup interval for automatic refresh. + * @param seconds - interval in millis. if zero or less than zero - automatic refresh disabled; + */ + virtual void setAutoRefreshInterval(int millis) = 0; + + /** + * @brief autoRefreshInterval - returns automatic refresh interval in millis + * @return + */ + virtual int autoRefreshInterval() const = 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 b4bc86f91..87e0cc935 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -36,6 +36,8 @@ #include <boost/filesystem.hpp> #include <boost/algorithm/string.hpp> +#include <boost/asio.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> #include <iostream> #include <vector> @@ -63,29 +65,28 @@ const char * WALLET_PASS = "password"; const char * WALLET_PASS2 = "password22"; const char * WALLET_LANG = "English"; -// change this according your environment - -const std::string WALLETS_ROOT_DIR = "/home/mbg033/dev/monero/testnet/"; - -const std::string TESTNET_WALLET1_NAME = WALLETS_ROOT_DIR + "wallet_01.bin"; -const std::string TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "wallet_02.bin"; -const std::string TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "wallet_03.bin"; -const std::string TESTNET_WALLET4_NAME = WALLETS_ROOT_DIR + "wallet_04.bin"; -const std::string TESTNET_WALLET5_NAME = WALLETS_ROOT_DIR + "wallet_05.bin"; -const std::string TESTNET_WALLET6_NAME = WALLETS_ROOT_DIR + "wallet_06.bin"; +std::string WALLETS_ROOT_DIR = "/var/monero/testnet_pvt"; +std::string TESTNET_WALLET1_NAME; +std::string TESTNET_WALLET2_NAME; +std::string TESTNET_WALLET3_NAME; +std::string TESTNET_WALLET4_NAME; +std::string TESTNET_WALLET5_NAME; +std::string TESTNET_WALLET6_NAME; const char * TESTNET_WALLET_PASS = ""; -const std::string CURRENT_SRC_WALLET = TESTNET_WALLET1_NAME; -const std::string CURRENT_DST_WALLET = TESTNET_WALLET6_NAME; +std::string CURRENT_SRC_WALLET; +std::string CURRENT_DST_WALLET; -const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; const uint64_t AMOUNT_10XMR = 10000000000000L; const uint64_t AMOUNT_5XMR = 5000000000000L; const uint64_t AMOUNT_1XMR = 1000000000000L; const std::string PAYMENT_ID_EMPTY = ""; +std::string TESTNET_DAEMON_ADDRESS = "localhost:38081"; + + } @@ -179,10 +180,8 @@ struct WalletTest2 : public testing::Test wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); } - }; - TEST_F(WalletManagerTest, WalletManagerCreatesWallet) { @@ -220,6 +219,7 @@ TEST_F(WalletManagerTest, WalletMaxAmountAsString) } + TEST_F(WalletManagerTest, WalletAmountFromString) { uint64_t amount = Bitmonero::Wallet::amountFromString("18446740"); @@ -394,6 +394,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } + TEST_F(WalletManagerTest, WalletManagerStoresWallet3) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -406,7 +407,8 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3) wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR_NON_WRITABLE, WALLET_PASS); ASSERT_FALSE(wallet1->status() == Bitmonero::Wallet::Status_Ok); - ASSERT_FALSE(wmgr->closeWallet(wallet1)); + // "close" always returns true; + ASSERT_TRUE(wmgr->closeWallet(wallet1)); wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok); @@ -416,6 +418,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3) } + TEST_F(WalletManagerTest, WalletManagerStoresWallet4) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -451,14 +454,14 @@ TEST_F(WalletManagerTest, WalletManagerFindsWallet) } -TEST_F(WalletManagerTest, WalletGeneratesPaymentId) +TEST_F(WalletTest1, WalletGeneratesPaymentId) { std::string payment_id = Bitmonero::Wallet::genPaymentId(); ASSERT_TRUE(payment_id.length() == 16); } -TEST_F(WalletManagerTest, WalletGeneratesIntegratedAddress) +TEST_F(WalletTest1, WalletGeneratesIntegratedAddress) { std::string payment_id = Bitmonero::Wallet::genPaymentId(); @@ -470,8 +473,6 @@ TEST_F(WalletManagerTest, WalletGeneratesIntegratedAddress) TEST_F(WalletTest1, WalletShowsBalance) { - // TODO: temporary disabled; - return; Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); ASSERT_TRUE(wallet1->balance() > 0); ASSERT_TRUE(wallet1->unlockedBalance() > 0); @@ -488,8 +489,35 @@ TEST_F(WalletTest1, WalletShowsBalance) ASSERT_TRUE(wmgr->closeWallet(wallet2)); } +TEST_F(WalletTest1, WalletReturnsCurrentBlockHeight) +{ + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + ASSERT_TRUE(wallet1->blockChainHeight() > 0); + wmgr->closeWallet(wallet1); +} + + +TEST_F(WalletTest1, WalletReturnsDaemonBlockHeight) +{ + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + // wallet not connected to daemon + ASSERT_TRUE(wallet1->daemonBlockChainHeight() == 0); + ASSERT_TRUE(wallet1->status() != Bitmonero::Wallet::Status_Ok); + ASSERT_FALSE(wallet1->errorString().empty()); + wmgr->closeWallet(wallet1); + + wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + // wallet connected to daemon + wallet1->init(TESTNET_DAEMON_ADDRESS, 0); + ASSERT_TRUE(wallet1->daemonBlockChainHeight() > 0); + std::cout << "daemonBlockChainHeight: " << wallet1->daemonBlockChainHeight() << std::endl; + wmgr->closeWallet(wallet1); +} + + TEST_F(WalletTest1, WalletRefresh) { + 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)); @@ -497,7 +525,6 @@ TEST_F(WalletTest1, WalletRefresh) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } - TEST_F(WalletTest1, WalletConvertsToString) { std::string strAmount = Bitmonero::Wallet::displayAmount(AMOUNT_5XMR); @@ -512,6 +539,7 @@ TEST_F(WalletTest1, WalletConvertsToString) TEST_F(WalletTest1, WalletTransaction) + { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -538,6 +566,8 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } + + TEST_F(WalletTest1, WalletTransactionWithMixin) { @@ -736,8 +766,10 @@ struct MyWalletListener : public Bitmonero::WalletListener std::condition_variable cv_receive; std::condition_variable cv_update; std::condition_variable cv_refresh; + std::condition_variable cv_newblock; bool send_triggered; bool receive_triggered; + bool newblock_triggered; bool update_triggered; bool refresh_triggered; @@ -775,6 +807,14 @@ struct MyWalletListener : public Bitmonero::WalletListener cv_receive.notify_one(); } + virtual void newBlock(uint64_t height) + { + std::cout << "wallet: " << wallet->address() + <<", new block received, blockHeight: " << height << std::endl; + newblock_triggered = true; + cv_newblock.notify_one(); + } + virtual void updated() { std::cout << __FUNCTION__ << "Wallet updated"; @@ -792,6 +832,8 @@ struct MyWalletListener : public Bitmonero::WalletListener }; + + TEST_F(WalletTest2, WalletCallBackRefreshedSync) { @@ -800,13 +842,15 @@ TEST_F(WalletTest2, WalletCallBackRefreshedSync) 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<std::mutex> lock (wallet_src_listener->mutex); -// wallet_src_listener->cv_refresh.wait_for(lock, wait_for); + std::chrono::seconds wait_for = std::chrono::seconds(60*3); + std::unique_lock<std::mutex> lock (wallet_src_listener->mutex); + wallet_src_listener->cv_refresh.wait_for(lock, wait_for); wmgr->closeWallet(wallet_src); } + + TEST_F(WalletTest2, WalletCallBackRefreshedAsync) { @@ -869,16 +913,17 @@ TEST_F(WalletTest2, WalletCallbackSent) TEST_F(WalletTest2, WalletCallbackReceived) { - Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET5_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()); - std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; + std::cout << "** Balance src1: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; 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(); + std::cout << "** Balance dst1: " << wallet_dst->displayAmount(wallet_dst->balance()) << std::endl; MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst); uint64_t amount = AMOUNT_1XMR * 5; @@ -900,7 +945,10 @@ TEST_F(WalletTest2, WalletCallbackReceived) 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; + + std::cout << "** Balance src2: " << wallet_dst->displayAmount(wallet_src->balance()) << std::endl; + std::cout << "** Balance dst2: " << wallet_dst->displayAmount(wallet_dst->balance()) << std::endl; + ASSERT_TRUE(wallet_dst->balance() > balance); wmgr->closeWallet(wallet_src); @@ -909,9 +957,61 @@ TEST_F(WalletTest2, WalletCallbackReceived) +TEST_F(WalletTest2, WalletCallbackNewBlock) +{ + + 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()); + uint64_t bc1 = wallet_src->blockChainHeight(); + std::cout << "** Block height: " << bc1 << std::endl; + + + MyWalletListener * wallet_listener = new MyWalletListener(wallet_src); + + // wait max 4 min for new block + std::chrono::seconds wait_for = std::chrono::seconds(60*4); + std::unique_lock<std::mutex> lock (wallet_listener->mutex); + std::cerr << "TEST: waiting on newblock lock...\n"; + wallet_listener->cv_newblock.wait_for(lock, wait_for); + std::cerr << "TEST: newblock lock acquired...\n"; + ASSERT_TRUE(wallet_listener->newblock_triggered); + uint64_t bc2 = wallet_src->blockChainHeight(); + std::cout << "** Block height: " << bc2 << std::endl; + ASSERT_TRUE(bc2 > bc1); + wmgr->closeWallet(wallet_src); + +} + + + int main(int argc, char** argv) { + // we can override default values for "TESTNET_DAEMON_ADDRESS" and "WALLETS_ROOT_DIR" + + const char * monero_daemon_addr = std::getenv("TESTNET_DAEMON_ADDRESS"); + if (monero_daemon_addr) { + TESTNET_DAEMON_ADDRESS = monero_daemon_addr; + } + + const char * wallets_root_dir = std::getenv("WALLETS_ROOT_DIR"); + if (wallets_root_dir) { + WALLETS_ROOT_DIR = wallets_root_dir; + } + + + TESTNET_WALLET1_NAME = WALLETS_ROOT_DIR + "/wallet_01.bin"; + TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "/wallet_02.bin"; + TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "/wallet_03.bin"; + TESTNET_WALLET4_NAME = WALLETS_ROOT_DIR + "/wallet_04.bin"; + TESTNET_WALLET5_NAME = WALLETS_ROOT_DIR + "/wallet_05.bin"; + TESTNET_WALLET6_NAME = WALLETS_ROOT_DIR + "/wallet_06.bin"; + + CURRENT_SRC_WALLET = TESTNET_WALLET6_NAME; + CURRENT_DST_WALLET = TESTNET_WALLET5_NAME; ::testing::InitGoogleTest(&argc, argv); + // Bitmonero::WalletManagerFactory::setLogLevel(Bitmonero::WalletManagerFactory::LogLevel_Max); return RUN_ALL_TESTS(); } diff --git a/tests/libwallet_api_tests/scripts/README.md b/tests/libwallet_api_tests/scripts/README.md new file mode 100644 index 000000000..2705cc04b --- /dev/null +++ b/tests/libwallet_api_tests/scripts/README.md @@ -0,0 +1,24 @@ +# Running libwallet_api tests + +## Environment for the tests +* Running monero node, linked to private/public testnet. + By default, tests expect daemon running at ```localhost:38081```, + can we overriden with enviroment variable ```TESTNET_DAEMON_ADDRESS=<your_daemon_address>``` + [Manual](https://github.com/moneroexamples/private-testnet) explaining how to run private testnet. + +* Directory with pre-generated wallets + (wallet_01.bin, wallet_02.bin,...,wallet_06.bin, some of these wallets might not be used in the tests currently). + By default, tests expect these wallets to be in ```/var/monero/testnet_pvt```. + Directory can be overriden with environment variable ```WALLETS_ROOT_DIR=<your_directory_with_wallets>```. + Directory and files should be writable for the user running tests. + + +## Generating test wallets +* ```create_wallets.sh``` - this script will create wallets (wallet_01.bin, wallet_02.bin,...,wallet_06.bin) in current directory. + when running first time, please uncomment line ```#create_wallet wallet_m``` to create miner wallet as well. + This wallet should be used for mining and all test wallets supposed to be seed from this miner wallet + +* ```mining_start.sh``` and ```mining_stop.sh``` - helper scripts to start and stop mining on miner waller + +* ```send_funds.sh``` - script for seeding test wallets. Please run this script when you have ehough money on miner wallet + diff --git a/tests/libwallet_api_tests/scripts/create_wallets.sh b/tests/libwallet_api_tests/scripts/create_wallets.sh index e25d2c317..f33564e7f 100755 --- a/tests/libwallet_api_tests/scripts/create_wallets.sh +++ b/tests/libwallet_api_tests/scripts/create_wallets.sh @@ -6,7 +6,6 @@ function create_wallet { } - create_wallet wallet_01.bin create_wallet wallet_02.bin create_wallet wallet_03.bin @@ -14,7 +13,6 @@ create_wallet wallet_04.bin create_wallet wallet_05.bin create_wallet wallet_06.bin - -#create_wallet wallet_m +# create_wallet wallet_m diff --git a/tests/libwallet_api_tests/scripts/send_funds.sh b/tests/libwallet_api_tests/scripts/send_funds.sh index b7f282b71..3ce923353 100755 --- a/tests/libwallet_api_tests/scripts/send_funds.sh +++ b/tests/libwallet_api_tests/scripts/send_funds.sh @@ -1,7 +1,5 @@ #!/bin/bash - - function send_funds { local amount=$1 local dest=$(cat "$2.address.txt") diff --git a/utils/gpg_keys/luigi1111.asc b/utils/gpg_keys/luigi1111.asc new file mode 100644 index 000000000..4ac3de627 --- /dev/null +++ b/utils/gpg_keys/luigi1111.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFdodc4BCAC02POyrMUol+nTXeZ2nCKM9G1Q2oU5jQLaQLNLUU88PHLdOVGd +nKh0QA4Uc4CA2wWU5zdIVFEzowUUNyKeSLJZhvOXbpN+pm6n9XiyNSZSDJhvMtAs +FEcyWyAjPAQT7MFS2SJgG7HhcoMAgr3ypp8FpAK2YwbfjfPqs5VFVdrYrVPfiSVJ +NTSoJMW+2oOUdTR/L6z8lzUZu0CH8aJK1Qqr0yyxbJelayPsos3aRQ9TQAu6u/zQ +PxURHaLTe8RsB6oa6wXnpZtXcl1xaigvlkNVpeHPbroBvhJoCbAFHC/edaBNBLiP +I3WCRGiCvvP2kIfuZlyv48gFX+E3NWSB10Q1ABEBAAG0IGx1aWdpMTExMSA8bHVp +Z2kxMTExd0BnbWFpbC5jb20+iQE4BBMBAgAiBQJXaHXOAhsDBgsJCAcDAgYVCAIJ +CgsEFgIDAQIeAQIXgAAKCRD0rKAYNkHgEAyoB/9agBv/xdNUgTVheW/O6kWG4DYG +/1mMfuTF1xi8CSFbUID3dRhnjXtncuSCaY7030CSLtnC/Pl8MnKHmcBZcoCiARzI +bNFK4dEdJjDU8yiqD+M0IAe58xCYQ7I/RX5TXJJ+WTS3lwi1zBqf9D4XVTQxSm+u +3tVH5mUu35pRWVCg1OSwWo1IGkSDkeGq8ySdYUJdM535caKf8L1ICNir1H7pWNCa +Jya/b3PRtSefw4tNHcsFtndl4S52iMdXwNUdwRKTP/hDa9KYxQqTGDtJ6nKjTy6p +dgZxAiF2mL9dVYg6c+GHlrtZMUZd5NQZcIwu9jXzAiQKZMmtL6/RauzXRuz9uQEN +BFdodc4BCADACy78WJBKCR4MrUcy4L0G4P5n+cqao2Lf+oc53xJudhcgufowsvzs +nixKG9HC+6SoZCZwKYfglu0JxjvqpZC5U9nCwIWuf52Qu4pDO4xYTeuhVr+Lcjvg +tqtJf5M9QaVJwAz8jTKaEAWUSXuKnljVC76zU8LTprYrTEdOyHO9E6Z94MrBUwS3 +6IVNlJ+q5wZyoj9noWbm7X0SIRER9/shr/UlfkSx0Kpnyj3ludkdg7TQR7jp9rGy +GqRmOKH3eGv2aFO1fo+RDacn+R9Fh1vHIdUX6FZil+yft9lXg5jtxcNXvhIJtsoC +NuVIWEYaQuzSFqtblTrM6IwJ8HrimEBPABEBAAGJAR8EGAECAAkFAldodc4CGwwA +CgkQ9KygGDZB4BBnEAf+OSvWLNJs0VtKRIO5oHP7Ia6oS8v0IyXFLx2/p/JW7jMR +3LVor2wvao52omW+JzoIj4J8cnaEEt2ptHpmzZApSQydZhHO+108hPDYbeWPrXa8 +aSXCtI++s2occAemsMvgrnzI7yuMFaAwOWOYL5bmR5pJnnuQQUj1vfXkqBEYYFyF +u7dvJ3hLHLbxBFvIbDBMfzev+g6wOGkhT2/7osUACoLwTwzkbXZNSoQHiZ72YA/P +9f3SA5Zc5hGopft96sAAnzk6sm/xCfFO1uj6Yk/H/fd/ZjVzQW+XBUvwM/jIqpuX +Ftwy4Ulp0YZT5BpXkHDhosL6o4GelJULMbxreh7nNQ== +=j0V6 +-----END PGP PUBLIC KEY BLOCK-----
\ No newline at end of file |